# How to Add a New API Endpoint to the FastAPI Application in Open Notebook

> Learn to add a new API endpoint to your FastAPI application in Open Notebook. This guide details creating router modules, implementing functions with Pydantic validation, and registering your endpoint.

- Repository: [Luis Novo/open-notebook](https://github.com/lfnovo/open-notebook)
- Tags: how-to-guide
- Published: 2026-06-27

---

**To add a new API endpoint to the Open Notebook FastAPI application, create a router module under `api/routers/`, implement the endpoint function with Pydantic validation, and register it in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) using `app.include_router()` with the appropriate prefix and tags.**

Open Notebook uses a modular FastAPI backend organized by feature-specific routers. When you add a new API endpoint to the FastAPI application in Open Notebook, you follow the established pattern found in files like [`api/routers/notebooks.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/notebooks.py) and [`api/routers/notes.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/notes.py). This approach keeps the codebase organized and automatically generates OpenAPI documentation at the `/docs` endpoint.

## Step 1: Create the Router Module

Start by creating a new Python file in the `api/routers/` directory. The repository follows a strict "router-per-feature" pattern, where each domain entity has its own module.

Create [`api/routers/hello.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/hello.py) (or your feature name) and instantiate an `APIRouter`:

```python
from fastapi import APIRouter, HTTPException

router = APIRouter()

@router.get("/hello")
async def say_hello(name: str = "world"):
    """Return a friendly greeting."""
    return {"message": f"Hello, {name}!"}

```

For a complete implementation example, reference [`api/routers/notebooks.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/notebooks.py), which demonstrates the full pattern including validation, repository calls, and error handling.

## Step 2: Define Pydantic Models (Optional)

If your endpoint requires request bodies or typed responses, define **Pydantic models** in [`api/models.py`](https://github.com/lfnovo/open-notebook/blob/main/api/models.py). The existing routers import schemas from this central location to ensure consistency across the API.

For example, the notebook router uses `NotebookCreate` and `NotebookResponse` models defined in this file. Add your models here when you need structured data validation:

```python
from pydantic import BaseModel

class NoteCreate(BaseModel):
    title: str
    content: str
    note_type: str

class NoteResponse(BaseModel):
    id: str
    title: str
    content: str

```

## Step 3: Implement the Endpoint Function

Write an **async function** that handles the request logic. Follow these conventions from the Open Notebook source code:

- Use type annotations for parameters (`Query`, `Path`, or request body types)
- Raise `HTTPException` for error handling
- Call domain objects from `open_notebook/domain/` (e.g., `Note`, `Notebook`)
- Use database utilities like `repo_query` or `ensure_record_id` from [`open_notebook/database/repository.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/repository.py)

Here is a complete example based on the pattern in [`api/routers/notes.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/notes.py):

```python
from fastapi import APIRouter, HTTPException
from api.models import NoteCreate, NoteResponse
from open_notebook.domain.notebook import Note

router = APIRouter()

@router.post("/notes", response_model=NoteResponse)
async def create_note(note: NoteCreate):
    try:
        new_note = Note(
            title=note.title,
            content=note.content,
            note_type=note.note_type,
        )
        await new_note.save()
        return NoteResponse(id=new_note.id, title=new_note.title, content=new_note.content)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

```

## Step 4: Register the Router in the FastAPI Application

Open [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) and import your new router module. The main application file already includes dozens of routers; add your registration line alongside the existing ones.

Add the `include_router` call with the standard `/api` prefix and appropriate tags for documentation grouping:

```python

# api/main.py

from api.routers import hello  # Import your new router

# ... existing app initialization ...

app.include_router(hello.router, prefix="/api", tags=["hello"])

```

The `prefix="/api"` parameter ensures all routes follow the standard URL structure, while `tags` organize endpoints in the automatically generated Swagger UI documentation.

## Complete Working Example

Here is the minimal code required to add a functional endpoint to Open Notebook:

**File:** [`api/routers/hello.py`](https://github.com/lfnovo/open-notebook/blob/main/api/routers/hello.py)

```python
from fastapi import APIRouter, HTTPException

router = APIRouter()

@router.get("/hello/{name}")
async def read_hello(name: str):
    if not name:
        raise HTTPException(status_code=400, detail="Name is required")
    return {"message": f"Hello, {name}!"}

```

**File:** [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) (add near other router imports)

```python
from api.routers import hello

app.include_router(hello.router, prefix="/api", tags=["hello"])

```

After registering, the endpoint becomes available at `/api/hello/{name}` and appears in the Swagger documentation at `/docs`.

## Key Source Files and Architecture

Understanding these files helps you follow the established patterns when adding endpoints:

- **[`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py)** — The FastAPI entry point that aggregates all routers and configures the application.
- **`api/routers/<feature>.py`** — Individual router modules (e.g., [`notebooks.py`](https://github.com/lfnovo/open-notebook/blob/main/notebooks.py), [`notes.py`](https://github.com/lfnovo/open-notebook/blob/main/notes.py)) containing endpoint definitions.
- **[`api/models.py`](https://github.com/lfnovo/open-notebook/blob/main/api/models.py)** — Central location for Pydantic request/response schemas shared across routers.
- **[`open_notebook/domain/notebook.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/domain/notebook.py)** — Domain objects like `Notebook` and `Note` that encapsulate business logic.
- **[`open_notebook/database/repository.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/repository.py)** — Database utilities including `repo_query` and `ensure_record_id` that routers call for data persistence.

## Summary

- **Create** a new router file in `api/routers/` using `APIRouter` to define your endpoints.
- **Define** Pydantic models in [`api/models.py`](https://github.com/lfnovo/open-notebook/blob/main/api/models.py) for type-safe request and response validation.
- **Implement** async endpoint functions that use domain objects from `open_notebook/domain/` and handle errors with `HTTPException`.
- **Register** the router in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py) using `app.include_router()` with `prefix="/api"` and appropriate tags.
- **Test** your endpoint using the Swagger UI at `/docs` or by running `uvicorn api.main:app`.

## Frequently Asked Questions

### Where should I define Pydantic models for my new endpoint?

Define Pydantic models in [`api/models.py`](https://github.com/lfnovo/open-notebook/blob/main/api/models.py). This file serves as the central schema repository for the entire FastAPI application, used by routers like [`notebooks.py`](https://github.com/lfnovo/open-notebook/blob/main/notebooks.py) to validate requests and serialize responses consistently.

### How do I handle database operations in my new endpoint?

Import domain objects from `open_notebook/domain/` (such as `Note` or `Notebook`) and use methods like `save()` or utilities from [`open_notebook/database/repository.py`](https://github.com/lfnovo/open-notebook/blob/main/open_notebook/database/repository.py) such as `repo_query` and `ensure_record_id`. This follows the repository pattern used throughout the codebase.

### Does FastAPI automatically document my new endpoint?

Yes. When you register the router with the `tags` parameter in `app.include_router()`, FastAPI automatically generates OpenAPI documentation at the `/docs` endpoint. No additional configuration is required for basic documentation.

### What is the standard URL prefix for API routes in Open Notebook?

The standard prefix is `/api`. When registering your router in [`api/main.py`](https://github.com/lfnovo/open-notebook/blob/main/api/main.py), always include `prefix="/api"` in the `include_router` call to maintain consistency with existing endpoints like `/api/notebooks` and `/api/notes`.