How to Add a Custom API Endpoint in the FastAPI Backend (Open Notebook)
To add a custom API endpoint in Open Notebook's FastAPI backend, create a new APIRouter in api/routers/, define Pydantic models in api/models.py, and register the router in api/main.py using app.include_router() with the /api prefix.
Open Notebook is an open-source project that uses FastAPI to serve its REST API, following a modular architecture where endpoints are organized by functional area. Understanding the router pattern used in the existing codebase allows you to extend the API with custom endpoints that automatically inherit global middleware, CORS configuration, and authentication layers. The canonical implementation follows the pattern established in api/routers/notebooks.py and wired together in api/main.py.
Understanding the Router Architecture
Open Notebook's API structure follows FastAPI's recommended best practices for larger applications:
- Modular routers: Each domain lives in its own module under
api/routers/. - Centralized schema: Request and response models are defined in
api/models.pyusing Pydantic. - Application factory: The main FastAPI instance is constructed in
api/main.py, where all routers are included with specific prefixes and tags.
In api/routers/notebooks.py, the router is instantiated on line 17 using router = APIRouter(), which serves as the reference pattern for new modules.
Step-by-Step Implementation
Create the Router File
Create a new Python file in the routers directory. The standard convention places new functionality in api/routers/custom.py (or a descriptive name matching your feature).
# api/routers/custom.py
from fastapi import APIRouter, HTTPException
from api.models import ExampleResponse
from loguru import logger
router = APIRouter()
This mirrors the instantiation pattern found at the top of existing router files like api/routers/notebooks.py.
Define Pydantic Schemas
Add your request and response models to api/models.py to ensure automatic validation and OpenAPI documentation generation:
# api/models.py
from pydantic import BaseModel
class ExampleResponse(BaseModel):
"""Response model for the example endpoint."""
message: str
Keeping schemas centralized in api/models.py maintains consistency across the codebase and makes dependencies between routers easier to manage.
Implement Endpoint Logic
Define your path operations using the standard FastAPI decorator syntax. The following example demonstrates a simple GET endpoint with query parameter handling:
# api/routers/custom.py
@router.get("/custom/hello", response_model=ExampleResponse)
async def hello(name: str = "world"):
"""Return a friendly greeting."""
logger.info(f"hello endpoint called with name={name}")
return ExampleResponse(message=f"Hello, {name}!")
Open Notebook uses loguru for structured logging, as imported in the router setup above. Error handling should use HTTPException from FastAPI to return appropriate status codes.
Register with the FastAPI App
Import and include your new router in api/main.py, following the pattern used for the notebook router on lines 92-94:
# api/main.py
from api.routers import custom # Add this import
# ... existing router registrations ...
app.include_router(custom.router, prefix="/api", tags=["custom"])
The prefix="/api" parameter ensures your endpoint appears under the /api path alongside existing endpoints. The tags parameter groups the endpoint under a named section in the auto-generated Swagger UI.
Complete Working Example
Here is the full implementation required to add a functional custom endpoint:
# ------------------------------
# api/models.py (add this class)
# ------------------------------
from pydantic import BaseModel
class ExampleResponse(BaseModel):
message: str
# ------------------------------
# api/routers/custom.py (create this file)
# ------------------------------
from fastapi import APIRouter, HTTPException
from api.models import ExampleResponse
from loguru import logger
router = APIRouter()
@router.get("/custom/hello", response_model=ExampleResponse)
async def hello(name: str = "world"):
"""Simple demo endpoint that returns a greeting."""
logger.info(f"Received hello request for name={name}")
return ExampleResponse(message=f"Hello, {name}!")
# ------------------------------
# api/main.py (add these lines)
# ------------------------------
from api.routers import custom # New import
# After existing router registrations (around line 92-94)
app.include_router(custom.router, prefix="/api", tags=["custom"])
After implementation, restart the server using uvicorn api.main:app or the provided run_api.py script. The new endpoint will be available at http://localhost:5055/api/custom/hello and documented at http://localhost:5055/docs under the custom tag.
Key Files and References
| Path | Purpose |
|---|---|
api/main.py |
Creates the FastAPI app, configures global CORS, and includes all routers at lines 92-94. |
api/routers/notebooks.py |
Reference implementation showing the canonical router pattern (instantiation at line 17). |
api/models.py |
Central location for Pydantic request/response models. |
api/routers/custom.py |
Your new router file (to be created). |
run_api.py |
Convenience script to launch the API with uvicorn. |
Summary
- Instantiate
APIRouterin a new file underapi/routers/to encapsulate your endpoint logic. - Define Pydantic models in
api/models.pyfor automatic request validation and response serialization. - Register the router in
api/main.pyusingapp.include_router()with the/apiprefix to maintain URL consistency. - Leverage existing infrastructure such as
logurufor logging and the global error handling middleware already configured in the FastAPI app.
Frequently Asked Questions
Where should I place my custom endpoint code in Open Notebook?
Create a new file inside api/routers/ (e.g., api/routers/custom.py) and instantiate an APIRouter there. This keeps the codebase modular and follows the existing architectural pattern used by the notebook and other functional modules.
How do I ensure my custom endpoint appears in the Swagger documentation?
Define Pydantic models for your request and response schemas in api/models.py, then reference them in your router using the response_model parameter. When you register the router in api/main.py with a tags argument, the endpoints will appear grouped under that tag in the auto-generated Swagger UI at /docs.
Do I need to manually configure CORS or authentication for my new endpoint?
No. When you register your router in api/main.py using app.include_router(), the endpoint automatically inherits the global CORS middleware and authentication layers already configured in the FastAPI application instance. This centralized configuration in api/main.py applies to all included routers.
Can I use async/await in my custom endpoint functions?
Yes. Open Notebook's FastAPI backend fully supports async path operation functions. Use async def for your endpoint handlers, especially when performing I/O operations like database calls or external API requests, to ensure non-blocking execution.
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 →