How to Add New API Endpoints to the FastAPI Application in Open Notebook
To add a new endpoint in Open Notebook's FastAPI application, create a router in api/routers/, implement the service layer in a dedicated module, define Pydantic schemas, and register the router in api/main.py using app.include_router().
Open Notebook organizes its HTTP API using a three-layer pattern that separates routing, business logic, and data validation. When you need to add new API endpoints to the FastAPI application, following this established structure ensures consistency with the existing codebase and automatic integration with authentication and CORS middleware. The pattern is explicitly documented in api/CLAUDE.md (lines 35-43) and implemented across the router files in the lfnovo/open-notebook repository.
The Three-Layer Architecture Pattern
Open Notebook structures its FastAPI application into three distinct layers: routers (HTTP handling), services (business logic), and models (Pydantic validation). This separation keeps HTTP concerns isolated from database queries and AI invocations. As implemented in lfnovo/open-notebook, the entry point at api/main.py wires all components together after initializing middleware, ensuring every registered endpoint inherits security and error-handling behaviors.
Step-by-Step Implementation Guide
1. Create the Router in api/routers/
Create a new Python file in api/routers/ (e.g., my_feature.py) and instantiate an APIRouter. Define path operations using decorators like @router.get() or @router.post(), importing request/response schemas from api/models.py. Delegate all business logic to service functions rather than implementing it directly in the router. The existing api/routers/notes.py demonstrates this pattern with clean separation between HTTP status codes and data operations.
from fastapi import APIRouter, HTTPException
from api.models import MyFeatureRequest, MyFeatureResponse
from api.my_feature_service import run_my_feature
router = APIRouter()
@router.post("/my-feature", response_model=MyFeatureResponse)
async def my_feature_endpoint(payload: MyFeatureRequest):
try:
result = await run_my_feature(payload)
return MyFeatureResponse(**result)
except Exception as exc:
raise HTTPException(status_code=400, detail=str(exc))
2. Define Request and Response Models
Add Pydantic schemas to api/models.py or create a dedicated models file (e.g., api/my_feature_models.py). Use Field descriptions, validators, and Literal constraints to enforce type safety. The existing NoteCreate, NoteResponse, and NoteUpdate models in api/models.py illustrate the expected patterns for validation.
from pydantic import BaseModel, Field
class MyFeatureRequest(BaseModel):
id: str = Field(..., description="Identifier of the resource")
class MyFeatureResponse(BaseModel):
result: dict
status: str
3. Implement the Service Layer
Create a service module (e.g., api/my_feature_service.py) containing async functions that handle core logic. These functions interact with SurrealDB through repo_query, invoke LangGraph graphs, or call external AI services. The router forwards validated input to these functions, keeping the HTTP layer thin. Reference api/sources_service.py for an example of database interaction and business logic encapsulation.
from open_notebook.database.repository import repo_query
from api.models import MyFeatureRequest
async def run_my_feature(req: MyFeatureRequest) -> dict:
data = await repo_query("SELECT * FROM my_data WHERE id = $id", {"id": req.id})
return {"result": data, "status": "ok"}
4. Register the Router in api/main.py
Import the new router at the top of api/main.py and register it with app.include_router(my_feature.router, tags=["my_feature"]). Registration occurs after CORS and authentication middleware are added, ensuring the new endpoint inherits these behaviors automatically. This centralizes route discovery and applies global exception handling.
from api.routers import my_feature
app.include_router(my_feature.router, tags=["my_feature"])
Testing and Verification
Launch the application with uv run uvicorn api.main:app --host 0.0.0.0 --port 5055 and verify the endpoint appears in the OpenAPI documentation at http://localhost:5055/docs. Unit tests should import service functions directly to bypass HTTP overhead, or use FastAPI's TestClient for integration testing against the actual router.
Summary
- Create an
APIRouterinapi/routers/to handle HTTP requests and responses, following the pattern inapi/routers/notes.py - Define Pydantic models in
api/models.pyfor request validation and serialization, usingFieldand validators as shown in existing schemas - Implement business logic in async service functions within dedicated modules (e.g.,
api/sources_service.py) rather than in routers - Register new routers in
api/main.pyusingapp.include_router()after middleware setup to inherit authentication and CORS behaviors - Test endpoints using the interactive docs at
/docsor FastAPI'sTestClientto verify correct integration
Frequently Asked Questions
Where should I place the business logic when adding a new FastAPI endpoint?
Place business logic in a dedicated service module (e.g., api/my_feature_service.py) rather than inside the router. This keeps the HTTP layer focused on request/response handling while service functions manage database queries through repo_query and AI integrations, as demonstrated in api/sources_service.py.
How do I ensure my new endpoint uses Open Notebook's authentication middleware?
Register the router in api/main.py using app.include_router() after the authentication and CORS middleware are initialized. The registration order in api/main.py ensures all registered routers inherit these security behaviors automatically, without requiring additional configuration in the router file.
Can I create separate model files instead of adding to api/models.py?
Yes, you can create dedicated model files (e.g., api/my_feature_models.py) for complex features. Import these schemas into your router just as you would from api/models.py, following the Pydantic patterns demonstrated in existing models like NoteCreate and NoteResponse with proper Field definitions and type constraints.
What is the recommended way to test new endpoints in Open Notebook?
Use FastAPI's TestClient for endpoint integration tests or import service functions directly for unit testing. Verify implementation by running uv run uvicorn api.main:app --host 0.0.0.0 --port 5055 and checking the OpenAPI documentation at http://localhost:5055/docs to confirm the route appears with correct schemas and tags.
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 →