Skip to content
Module 4 · API & Business LogicIntermediate3 min read · 662 words

Lesson 09: API Routers — Overview

"RESTful APIs: The language of the web."

Two Routers, One Prefix

Both routers mount at the same /agents prefix:

python
# main.py
app.include_router(agents.router)     # prefix="/agents", tags=["Agents"]
app.include_router(documents.router)  # prefix="/agents", tags=["Documents"]

FastAPI happily merges routers sharing a prefix — the OpenAPI docs (/docs) group them by tags instead, which is why Swagger shows an "Agents" section and a separate "Documents" section even though every URL starts with /agents.

The Full Endpoint Count

20 endpoints total across the two files — not 18, a number an earlier draft of this course used. Corrected count:

  • backend/app/routers/agents.py15 endpoints
  • backend/app/routers/documents.py5 endpoints
FileMethodPathPurpose
agents.pyPOST/agents/Create agent
agents.pyGET/agents/List all agents
agents.pyGET/agents/{id}Get single agent
agents.pyPOST/agents/{id}/chatChat with agent
agents.pyGET/agents/{id}/runsChat run history
agents.pyPOST/agents/{id}/email/analyzeAnalyze one email
agents.pyGET/agents/{id}/tasksList tasks for agent
agents.pyPUT/tasks/{id}/statusUpdate a task's status
agents.pyGET/agents/{id}/tool-callsList LLM call logs
agents.pyPOST/agents/{id}/workflows/emailRun multi-agent email workflow
agents.pyGET/agents/{id}/workflow-runsList workflow run history
agents.pyGET/workflow-runs/{id}/stepsSteps for one workflow run
agents.pyGET/agents/{id}/dashboardAggregated metrics
agents.pyGET/agents/{id}/messagesPaginated message history
agents.pyGET/agents/{id}/stats⚠️ Broken — see Lesson 09a
documents.pyPOST/agents/{id}/documents/uploadUpload a .txt document
documents.pyGET/agents/{id}/documentsList documents for agent
documents.pyGET/agents/{id}/chunksList chunks for agent
documents.pyPOST/agents/{id}/documents/searchRaw semantic search
documents.pyPOST/agents/{id}/documents/askCorrective-RAG question answering

For the line-by-line walkthrough of each, go to the dedicated lessons:

👉 Lesson 09a: Agents Router Deep Dive — all 15 endpoints, plus the 7 module-level helper functions. 👉 Lesson 09b: Documents Router Deep Dive — all 5 endpoints, the upload pipeline, and RAG entry point.

The Recurring Pattern

Every single endpoint in both files follows the same shape:

python
@router.post("/{agent_id}/chat", response_model=schemas.ChatResponse)
def chat_with_agent(agent_id: int, chat_data: schemas.ChatRequest, db: Session = Depends(get_db)):
    agent = db.query(models.Agent).filter(models.Agent.id == agent_id).first()
    if agent is None:
        raise HTTPException(status_code=404, detail="Agent not found")
    # ... call a service function ...
    # ... persist the result ...
    return result
  1. Validate input — Pydantic does this automatically before the function body even runs, via the chat_data: schemas.ChatRequest parameter.
  2. Check existence — a manual .filter(...).first() + if ... is None: raise HTTPException(404, ...). This is repeated in every single endpoint that takes an agent_id — 18 of the 20 endpoints. There is no shared dependency for this (see Lesson 10 for why that's a missed opportunity).
  3. Call a service function — the router never talks to OpenAI, ChromaDB, or builds prompts itself; it delegates to services/.
  4. Persist and returndb.add(...), db.commit(), db.refresh(...), then return an ORM object or a dict that FastAPI serializes through response_model.

Endpoints Without a response_model

Two endpoints skip the response_model= argument entirely: POST /agents/{id}/email/analyze and (implicitly, since it declares one but the body doesn't match it) the broken /stats endpoint. Skipping response_model means FastAPI returns whatever dict the function produces, unvalidated and undocumented in the OpenAPI schema — a smaller version of the same problem the /stats endpoint has in a worse form.

Key Patterns

✅ Validate input with Pydantic ✅ Check existence (404 if not found) ✅ Call service functions — routers never own business logic ✅ Log a ToolCall for anything that talks to an LLM ✅ Save to database, then return

Next Steps

👉 Lesson 09a: Agents Router Deep Dive →


Module 4 · API & Business Logic