Skip to content

Routers

Real world applications can almost never fit all logic into a single file.

Django Ninja comes with an easy way to split your API into multiple modules using Routers.

Let's say you have a Django project with a structure like this:

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

To add API's to each of the Django applications, create an api.py module in each app:

├── 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 a few 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 with 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 then also blogs/api.py.

Finally, let's group them together. In your top level project folder (next to urls.py), create another api.py file with the main 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 various apps, 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, include api to your urls as usual and open your browser at /api/docs, and you should see all your routers combined into a single API:

Swagger UI Simple Routers

Router authentication

Use auth argument to apply authenticator to all operations declared by router:

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

or using router constructor

router = Router(auth=BasicAuth())

Router tags

You can use tags argument to apply tags to all operations declared by router:

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

or using router constructor

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

Nested routers

There are also times when you need to split your logic up even more. Django Ninja makes it possible to include a router into another router as many times as you like, and finally include the top level router into the main api instance.

Basically, what that means is that you have add_router both on the api instance and on 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

Great! Now go have a look at the automatically generated docs:

Swagger UI Nested Routers