Skip to content

Splitting your API with routers

In the real world, it is almost impossible to keep all the logic in a single file.

Django Ninja provides a simple way to split your API into multiple modules using routers.

Suppose you have a Django project with the following structure:

├── myproject
│   └── settings.py
├── events/
│   ├── __init__.py
│   └── models.py
├── news/
│   ├── __init__.py
│   └── models.py
├── blogs/
│   ├── __init__.py
│   └── models.py
└── manage.py

To add an API to each Django application, create an api.py module in each application:

├── myproject
│   └── settings.py
├── events/
│   ├── __init__.py
│   ├── api.py
│   └── models.py
├── news/
│   ├── __init__.py
│   ├── api.py
│   └── models.py
├── blogs/
│   ├── __init__.py
│   ├── api.py
│   └── models.py
└── manage.py

Now let's add some operations to events/api.py. The trick is that instead of using the NinjaAPI class, you use the Router class:

from ninja import Router
from .models import Event

router = Router()

@router.get('/')
def list_events(request):
    return [
        {"id": e.id, "title": e.title}
        for e in Event.objects.all()
    ]

@router.get('/{event_id}')
def event_details(request, event_id: int):
    event = Event.objects.get(id=event_id)
    return {"title": event.title, "details": event.details}

Then do the same for the news app's news/api.py:

from ninja import Router
from .models import News

router = Router()

@router.get('/')
def list_news(request):
    ...

@router.get('/{news_id}')
def news_details(request, news_id: int):
    ...
And also blogs/api.py.

Finally, let's put it all together. In your top-level project folder (next to urls.py), create another api.py file with a NinjaAPI instance:

├── myproject
│   ├── api.py
│   └── settings.py
├── events/
│   ...
├── news/
│   ...
├── blogs/
│   ...

It should look like this:

from ninja import NinjaAPI

api = NinjaAPI()

Now we import all the routers from the individual applications and include them into the main API instance:

from ninja import NinjaAPI
from events.api import router as events_router

api = NinjaAPI()

api.add_router("/events/", events_router)    # You can add a router as an object
api.add_router("/news/", "news.api.router")  #   or by Python path
api.add_router("/blogs/", "blogs.api.router")

Now, add api to your URLs as usual and open your browser at /api/docs, you should see all your routers combined into a single API:

Swagger UI Simple Routers

Router authentication

Use the auth argument to apply an authenticator to all operations declared in a router:

api.add_router("/events/", events_router, auth=BasicAuth())

Or using the router constructor

router = Router(auth=BasicAuth())

Router tags

You can use the tags argument to apply tags to all operations declared in a router:

api.add_router("/events/", events_router, tags=["events"])

Or using the router constructor

router = Router(tags=["events"])

Nested routers

Sometimes you also need to split the logic further. Django Ninja lets you include a router inside another router any number of times, and finally include the top-level router into the main api instance.

Basically, this means you have add_router on both the api instance and the router instance:

from django.contrib import admin
from django.urls import path
from ninja import NinjaAPI, Router

api = NinjaAPI()

first_router = Router()
second_router = Router()
third_router = Router()


@api.get("/add")
def add(request, a: int, b: int):
    return {"result": a + b}


@first_router.get("/add")
def add(request, a: int, b: int):
    return {"result": a + b}


@second_router.get("/add")
def add(request, a: int, b: int):
    return {"result": a + b}


@third_router.get("/add")
def add(request, a: int, b: int):
    return {"result": a + b}


second_router.add_router("l3", third_router)
first_router.add_router("l2", second_router)
api.add_router("l1", first_router)

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/", api.urls),
]

Now you have the following endpoints

/api/add
/api/l1/add
/api/l1/l2/add
/api/l1/l2/l3/add

Awesome! Now go check the auto-generated documentation:

Swagger UI nested routers

Success

Continue to the next section Authentication

Comments


本文总阅读量次