Backend API (Django Ninja)

Backend API (Django Ninja)

Source of truth: backend/config/api.py.

Router Layout

AppNinjaAPI is mounted at /api/v1/ in backend/config/urls.py.

Key endpoints:

  • OpenAPI schema: /api/v1/openapi.json
  • OpenAPI schema (merged with allauth headless paths, for reference): /api/v1/openapi-merged.json
  • Human docs: /api/v1/docs/ (template at backend/templates/pages/api_docs.html)

Routers are added explicitly in backend/config/api.py, for example:

  • /billing/ -> backend/apps/payments/api/billing.py
  • /workspaces/ -> backend/apps/tenants/api/workspaces.py
  • /ai/chat/ -> backend/apps/ai/api.py

JSON Shape (camelCase In/Out)

Requests:

  • The API parser decamelizes JSON request bodies (ORJSONParser in backend/config/api.py), so clients can send camelCase and backend code can keep snake_case.

Responses:

  • Many response schemas use BASE_MODEL_CONFIG (backend/apps/common/schema.py) so fields serialize as camelCase.
  • Many endpoints pass by_alias=True so aliases are used in output.

Auth On The Ninja API

Ninja API auth is configured as a list in backend/config/api.py:

  1. django_auth (cookie-based browser sessions)
  2. headless_x_session_token_auth (header-based session token for non-cookie clients)

The frontend sends cookies plus X-Session-Token by default via Axios interceptors (frontend/lib/api-client.ts).

Error Handling

backend/config/api.py registers exception handlers for:

  • ORM lookups (ObjectDoesNotExist, Http404)
  • auth/permission errors (AuthenticationError, PermissionDenied)
  • validation (django.core.exceptions.ValidationError, Pydantic validation)

This is the place to look if the frontend sees unexpected error shapes.

Adding A New Endpoint (Pattern)

  1. Add/update a router under the relevant app.
  2. Define request/response schemas in that app (convention varies: many apps use schema.py, some use schemas.py).
  3. Mount the router in backend/config/api.py via api.add_router(...).
  4. Regenerate frontend hooks if needed: make create_spec.

Implementation tip:

  • Prefer small routers with thin endpoints.
  • Put business logic in model methods or services/ modules.

OpenAPI Operation IDs

AppNinjaAPI.get_openapi_operation_id() generates operation IDs based on router tag + function name. This impacts Orval hook names.

Last updated June 21, 2026