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 transcripts2. 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: intDelete operations return confirmation:
class DeleteResponse(BaseModel):
success: bool
message: str5. 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
| Router | Prefix | Endpoints |
|---|---|---|
| Auth | /api/v1/auth | login, register, refresh, me |
| Agents | /api/v1/agents | list, create, get, update, delete, activate, deactivate |
| Workflows | /api/v1/workflows | list, create, get, update, delete, activate, deactivate |
| Tools | /api/v1/tools | list, create, get, update, delete |
| Calls | /api/v1/calls | list, get, transcript, metrics, active |
| Analytics | /api/v1/analytics | summary, call-volume, workflow-stats, provider-latency, errors, active-calls |
| WebSocket | /ws | calls (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