How API Routes Are Registered and Organized with Tags in open-notebook's main.py
In lfnovo/open-notebook, every API route is registered inside api/main.py by importing modular APIRouter instances from api/routers/ and mounting them with app.include_router() using a shared /api prefix and a descriptive tags list that drives OpenAPI documentation grouping.
Managing a growing FastAPI backend requires a predictable registration pattern. In the lfnovo/open-notebook repository, the api/main.py file serves as the single source of truth for how API routes are registered and organized with tags, ensuring that Swagger UI stays clean and developers can locate endpoints quickly.
The Router Registry in api/main.py
According to the lfnovo/open-notebook source code, the FastAPI application instance is created in api/main.py. Rather than defining endpoints directly in that file, the project uses a modular router pattern that keeps the main bootstrap file focused solely on assembly.
All router modules live in the api/routers/ package and are imported in bulk near the top of api/main.py:
from api.routers import (
auth, chat, config, context, credentials, embedding,
embedding_rebuild, episode_profiles, insights, languages,
models, notebooks, notes, podcasts, search, settings,
source_chat, sources, speaker_profiles, transformations,
)
from api.routers import commands as commands_router
The commands router is imported separately as commands_router to avoid naming conflicts with the module itself.
After the FastAPI app is instantiated, each router is attached using the same consistent signature starting around line 89:
app.include_router(auth.router, prefix="/api", tags=["auth"])
app.include_router(config.router, prefix="/api", tags=["config"])
app.include_router(notebooks.router, prefix="/api", tags=["notebooks"])
# ... continues for all routers
The prefix="/api" argument guarantees that every endpoint in every router is mounted under the /api base path. The tags argument is a list that tells FastAPI how to group routes in the generated OpenAPI schema and the interactive Swagger UI.
Tag Mapping and OpenAPI Grouping
Because each call to app.include_router() supplies its own tags list, the resulting /docs page automatically organizes endpoints by functional area. Developers do not need to annotate every individual path operation with a tag because the router-level tag cascades to all endpoints in that module.
The concrete registrations in api/main.py map routers to tags as follows:
| Tag | Router | Source Lines |
|---|---|---|
auth |
auth.router |
L89–L91 |
config |
config.router |
L91–L92 |
notebooks |
notebooks.router |
L92–L93 |
search |
search.router |
L93–L94 |
models |
models.router |
L94–L95 |
transformations |
transformations.router |
L95–L96 |
notes |
notes.router |
L96–L97 |
embedding |
embedding.router |
L97–L98 |
embeddings |
embedding_rebuild.router |
L98–L100 |
settings |
settings.router |
L100–L101 |
context |
context.router |
L101–L102 |
sources |
sources.router |
L102–L103 |
insights |
insights.router |
L103–L104 |
commands |
commands_router.router |
L104–L106 |
podcasts |
podcasts.router |
L106–L108 |
episode-profiles |
episode_profiles.router |
L107–L109 |
speaker-profiles |
speaker_profiles.router |
L108–L110 |
chat |
chat.router |
L109–L111 |
source-chat |
source_chat.router |
L110–L112 |
credentials |
credentials.router |
L111–L113 |
languages |
languages.router |
L112–L114 |
When you start the application and visit /docs, endpoints appear under collapsible headings such as auth, notebooks, and transformations. This reduces cognitive load and mirrors the project's package structure.
Defining Routes Inside api/routers/
Each router file in api/routers/ exports an APIRouter instance named router. For example, api/routers/auth.py defines authentication-scoped endpoints without worrying about global prefixes or tags:
# api/routers/auth.py
from fastapi import APIRouter, Depends
router = APIRouter()
@router.get("/auth/status")
async def status():
return {"authenticated": True}
Because api/main.py registers this router with prefix="/api" and tags=["auth"], the effective endpoint is GET /api/auth/status and it appears under the auth group in the documentation.
Extending an Existing Router
You can add new endpoints to a group by modifying the relevant router file. The models router illustrates this pattern:
# api/routers/models.py
from fastapi import APIRouter
router = APIRouter()
@router.get("/models")
async def list_models():
return {"models": ["gpt-4", "claude"]}
@router.post("/models")
async def create_model(name: str):
# implementation …
return {"created": name}
Both methods are automatically prefixed with /api and grouped under the models tag because api/main.py already mounts models.router with those settings.
Testing Endpoints Programmatically
Routes registered through this system behave like standard FastAPI paths in tests. You can exercise them with an async HTTP client:
import httpx
import asyncio
async def test_health():
async with httpx.AsyncClient(base_url="http://localhost:5055") as client:
r = await client.get("/health")
assert r.json() == {"status": "healthy"}
asyncio.run(test_health())
The /health endpoint is defined directly in api/main.py outside the router system, but it follows the same FastAPI conventions as the tagged router endpoints.
Summary
api/main.pyacts as the single registry for every API router inlfnovo/open-notebook.- Routers are imported from the
api/routers/package and attached withapp.include_router(). - A universal
prefix="/api"ensures consistent URL paths across all modules. - The
tagsparameter on eachinclude_router()call drives OpenAPI and Swagger UI grouping. - Individual router files only need to export an
APIRouterinstance namedrouter.
Frequently Asked Questions
What is the base prefix for all API routes in open-notebook?
Every router imported into api/main.py is mounted with prefix="/api". Therefore, all endpoints exposed through the router system are reachable under the /api base path.
How do tags affect the Swagger UI documentation?
FastAPI uses the tags argument from app.include_router() to categorize endpoints in the auto-generated /docs interface. In lfnovo/open-notebook, each router receives a descriptive tag such as auth or notebooks, so related endpoints appear together.
Where are individual endpoint functions defined if not in main.py?
Endpoint functions live inside dedicated modules under api/routers/. For instance, authentication logic resides in api/routers/auth.py, while source management lives in api/routers/sources.py. Each module exports a router object that api/main.py consumes.
How can I add a new tag group to the API?
Create a new file in api/routers/ that instantiates an APIRouter, define your endpoints on that router, and then import the module in api/main.py. Add a line such as app.include_router(new_module.router, prefix="/api", tags=["new-tag"]) alongside the existing registrations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →