Agent Studio
Adr

ADR-007: REST API Router Architecture

Standardized router pattern for FastAPI endpoints

ADR-007: REST API Router Architecture

Status

Accepted

Context

Agent Studio requires a comprehensive REST API to support:

  • Dashboard UI interactions (agents, workflows, tools management)
  • Call monitoring and transcript retrieval
  • User authentication and session management
  • Server-to-server integrations via API keys

We needed to establish a consistent pattern for implementing API routers that:

  • Provides proper tenant isolation
  • Supports both JWT and API key authentication
  • Uses scope-based authorization
  • Follows REST conventions
  • Maintains type safety with Pydantic schemas

Decision

We implemented a standardized router architecture with the following patterns:

1. Router Structure

Each domain has its own router module in src/agent_studio/api/routers/:

routers/
├── __init__.py      # Exports all routers
├── health.py        # Health check endpoints
├── auth.py          # Authentication (login, register, refresh)
├── agents.py        # Agent CRUD operations
├── workflows.py     # Workflow CRUD operations
├── tools.py         # Tool CRUD operations
└── calls.py         # Call monitoring and transcripts

2. Dependency Injection Pattern

Each router uses a tenant-scoped repository pattern:

def get_agent_repo(
    session: DBSession,
    current_user: AuthenticatedUser,
) -> AgentRepository:
    return AgentRepository(session, current_user.tenant_id)

AgentRepo = Annotated[AgentRepository, Depends(get_agent_repo)]

This ensures:

  • Automatic tenant scoping for all queries
  • Database session lifecycle management
  • Authentication enforcement

3. Scope-Based Authorization

Endpoints declare required scopes using dependency injection:

@router.get("", response_model=PaginatedResponse[AgentResponse])
async def list_agents(
    repo: AgentRepo,
    current_user: Annotated[AuthenticatedUser, Depends(require_scope("agents:read"))],
    ...
)

Scope patterns:

  • {resource}:read - Read access
  • {resource}:write - Create/update access
  • {resource}:delete - Delete access
  • {resource}:* - Full access to resource
  • * - Admin access (all permissions)

4. Consistent Response Schemas

All list endpoints return paginated responses:

class PaginatedResponse(BaseModel, Generic[T]):
    items: list[T]
    total: int
    page: int
    page_size: int
    pages: int

Delete operations return confirmation:

class DeleteResponse(BaseModel):
    success: bool
    message: str

5. Resource Identification

  • Agents: Identified by name (unique per tenant)
  • Workflows: Identified by slug (unique per tenant)
  • Tools: Identified by name (unique per tenant)
  • Calls: Identified by id (UUID)

6. Router Registration

All routers are registered in app.py:

from agent_studio.api.routers import agents, auth, calls, tools, workflows

app.include_router(auth.router, prefix="/api/v1/auth", tags=["Auth"])
app.include_router(agents.router, prefix="/api/v1/agents", tags=["Agents"])
app.include_router(workflows.router, prefix="/api/v1/workflows", tags=["Workflows"])
app.include_router(tools.router, prefix="/api/v1/tools", tags=["Tools"])
app.include_router(calls.router, prefix="/api/v1/calls", tags=["Calls"])

Consequences

Positive

  • Consistent patterns: All routers follow the same structure, making the codebase predictable
  • Type safety: Full Pydantic validation on requests and responses
  • Automatic tenant isolation: Repository pattern ensures no cross-tenant data leakage
  • Flexible authorization: Scope-based system supports fine-grained permissions
  • OpenAPI documentation: Auto-generated from type annotations
  • Testability: Dependency injection makes routers easy to test

Negative

  • Boilerplate: Each router requires similar setup code (mitigated by patterns)
  • Repository per request: Creates new repository instance per request (acceptable overhead)

Neutral

  • Learning curve: Developers need to understand the DI pattern
  • Schema duplication: Some overlap between API schemas and domain models

Implementation Details

API Endpoints

RouterPrefixEndpoints
Auth/api/v1/authlogin, register, refresh, me
Agents/api/v1/agentslist, create, get, update, delete, activate, deactivate
Workflows/api/v1/workflowslist, create, get, update, delete, activate, deactivate
Tools/api/v1/toolslist, create, get, update, delete
Calls/api/v1/callslist, get, transcript, metrics, active
Analytics/api/v1/analyticssummary, call-volume, workflow-stats, provider-latency, errors, active-calls
WebSocket/wscalls (tenant events), calls/[call_id] (single call events)

Supporting Infrastructure

  • User model: Added for JWT authentication
  • Tool repository: CRUD operations with search
  • Call repository: Filtering, transcript management, status updates

On this page