Controllers and operations¶
Everything a controller, an operation decorator, routes and mount() accept.
Options merge in this order, later layers winning: NINJA_DEVX["DEFAULT_OPTIONS"],
Controller.options along the MRO, as_router(**options), operation options.
See the Controllers guide.
Controller class attributes¶
Base class for class-based Django Ninja controllers.
| Name | Type | Default | Description |
|---|---|---|---|
scope |
Scope |
Scope.REQUEST |
Scope.REQUEST: a controller per request (inside the DI scope); Scope.SINGLETON: one per as_router() call. |
mode |
Literal['sync', 'async', 'auto'] |
'sync' |
Which implementation to register when an operation has an async_variant; "auto" follows NINJA_DEVX["ASYNC_MODE"]. |
routes |
Mapping[str, RouteOptions] |
MappingProxyType({}) |
Overrides per operation name: {"bulk_create": {"path": "/batch"}, "destroy": {"enabled": False}, "list": {"summary": "Posts"}}. Unknown names fail at startup. |
options |
ControllerOptions |
ControllerOptions() |
Merged along the MRO over NINJA_DEVX["DEFAULT_OPTIONS"], then as_router(**options). |
Controller.as_router()¶
def as_router(*, container: ContainerLike | None = None, scope: Scope | None = None, **options: Unpack[ControllerOptions]) -> Router: ...
Build a new native Ninja Router exposing this controller's operations.
| Parameter | Type | Default | Description |
|---|---|---|---|
container |
ContainerLike \| None |
None |
Builds controllers and Inject[...] values: a Container, a dishka/svcs resolver, or any Resolver/RequestScopeProvider. |
scope |
Scope \| None |
None |
Overrides the class's scope for this router. |
**options |
Unpack[ControllerOptions] |
— | ControllerOptions over the class's options. |
ControllerOptions¶
Defaults for every operation of a controller.
| Name | Type | Default | Description |
|---|---|---|---|
auth |
AuthSpec |
— | Ninja authentication for every operation (django_auth, JWTAuth(), a list, or None). |
throttle |
ThrottleSpec |
— | Ninja throttles for every operation (UserRateThrottle("100/min") or a list). |
tags |
Sequence[str] |
— | OpenAPI tags. |
permissions |
Sequence[AnyPermission] |
— | Permissions checked before each operation (see Also for adding at operation level). |
decorators |
Sequence[ViewDecorator] |
— | View decorators (paginate(...), conditional()); the first item is outermost. |
hooks |
Sequence[OperationHook \| AsyncOperationHook] |
— | Operation hooks wrapping each call (sync around or async around_async). |
atomic |
bool \| Literal['durable'] |
— | Run sync operations in transaction.atomic(); "durable" must be the outermost. |
database |
str |
— | Database alias for atomic. |
errors |
ErrorMap |
— | Exception rules for every operation (see ninja_devx.http.errors). |
meta |
Sequence[object] |
— | Typed metadata read with get_operation(request).meta(Kind). |
plugins |
Sequence[ControllerPlugin] |
— | ControllerPlugin objects applied to every operation. |
middleware |
Sequence[Middleware] |
— | Router middleware around every operation, including auth and throttling (RequestIDMiddleware(), DeprecationMiddleware(sunset=...)). |
allow_mixed_path |
bool |
— | Silence the warning for a path served by both sync and async operations. |
deprecated |
bool |
— | Mark every operation deprecated in OpenAPI. |
document_errors |
bool |
— | Document 401/403/404/422 responses in OpenAPI (default from settings). |
by_alias |
bool |
— | Serialize responses by field alias (Ninja). |
exclude_unset |
bool |
— | Leave unset fields out of responses (Ninja). |
exclude_defaults |
bool |
— | Leave fields equal to their default out of responses (Ninja). |
exclude_none |
bool |
— | Leave None fields out of responses (Ninja). |
operation_id_prefix |
str |
— | Prepended to every operation id (mount(prefix=...) sets it for versions). |
url_name_prefix |
str |
— | Prepended (with _) to explicit url_name values. |
api_operation()¶
def api_operation(methods: str | Sequence[str], path: str = '/', **options: Unpack[OperationOptions]) -> Callable[[OperationMethod[C, RequestT, P, R]], OperationMethod[C, RequestT, P, R]]: ...
Mark a controller method as an operation for the given HTTP methods.
| Parameter | Type | Default | Description |
|---|---|---|---|
methods |
str \| Sequence[str] |
— | HTTP methods, e.g. ["GET", "HEAD"]. |
path |
str |
'/' |
Path relative to the router; {name} segments become parameters. |
**options |
Unpack[OperationOptions] |
— | OperationOptions: Ninja's operation keywords plus ninja-devx's. |
get(path="/", **options), post(...), put(...), patch(...) and
delete(...) take the same path and options as api_operation.
OperationOptions¶
Keyword arguments accepted by every operation decorator.
| Name | Type | Default | Description |
|---|---|---|---|
auth |
AuthSpec |
— | Ninja authentication for this operation; overrides the controller's. |
throttle |
ThrottleSpec |
— | Ninja throttles for this operation. |
response |
ResponseSpec |
— | Response schema, or {status: schema} (Ninja). |
operation_id |
str \| None |
— | OpenAPI operation id (default <controller>_<method>). |
summary |
str \| None |
— | OpenAPI summary. |
description |
str \| None |
— | OpenAPI description (default: the method docstring). |
tags |
list[str] \| None |
— | OpenAPI tags. |
deprecated |
bool \| None |
— | Mark the operation deprecated in OpenAPI. |
by_alias |
bool \| None |
— | Serialize the response by field alias (Ninja). |
exclude_unset |
bool \| None |
— | Leave unset fields out of the response (Ninja). |
exclude_defaults |
bool \| None |
— | Leave fields equal to their default out of the response (Ninja). |
exclude_none |
bool \| None |
— | Leave None fields out of the response (Ninja). |
url_name |
str \| None |
— | Django URL name for reverse(). |
include_in_schema |
bool |
— | Show the operation in OpenAPI. |
openapi_extra |
dict[str, JSONValue] \| None |
— | Merged into the operation's OpenAPI object. |
permissions |
Sequence[AnyPermission] |
— | Replaces the controller's permissions; Also(...) adds to them instead. |
decorators |
Sequence[ViewDecorator] |
— | View decorators applied inside the controller's ones; the first item is outermost. |
hooks |
Sequence[OperationHook \| AsyncOperationHook] |
— | Operation hooks run inside the controller's hooks. |
atomic |
bool \| Literal['durable'] |
— | Run the operation in transaction.atomic() ("durable": must be the outermost). |
database |
str |
— | Database alias for atomic. |
errors |
ErrorMap |
— | Exception rules for this operation, over the controller's. |
raises |
Sequence[type[BaseException]] |
— | Exceptions this operation may raise: documented in OpenAPI, checked against the rules. |
meta |
Sequence[object] |
— | Typed metadata read by permissions and hooks via get_operation(request).meta(Kind). |
document_errors |
bool |
— | Document 401/403/404/422 responses in OpenAPI (default from settings). |
RouteOptions¶
Per-operation overrides in Controller.routes (paths and options are not hard-coded).
Also accepts every OperationOptions key.
| Name | Type | Default | Description |
|---|---|---|---|
path |
str |
— | Replaces the declared path, e.g. {"restore": {"path": "/{pk}/undelete"}}. |
enabled |
bool |
— | False removes the operation from the router. |
async_variant()¶
Declare the async implementation of an operation, used when the controller runs async.
| Parameter | Type | Default | Description |
|---|---|---|---|
sync_method |
Callable[..., object] |
— | The sync operation this async method implements. |
use_case()¶
def use_case(decorator: Callable[[Method], Method], handler: Callable[..., UseCase[CommandT, ResultT] | UseCase[CommandT, Awaitable[ResultT]]], *, command: Callable[[PayloadT], CommandT], status: int | None = None) -> Method: ...
An operation method: map the payload with command and call the resolved handler.
| Parameter | Type | Default | Description |
|---|---|---|---|
decorator |
Callable[[Method], Method] |
— | The operation decorator, e.g. post("/", response={201: OrderOut}). |
handler |
Callable[..., UseCase[CommandT, ResultT] \| UseCase[CommandT, Awaitable[ResultT]]] |
— | A class with __call__(command) (sync or async), resolved from the container. |
command |
Callable[[PayloadT], CommandT] |
— | Maps the validated payload to the command; its parameter type is the request body. |
status |
int \| None |
None |
Status code of the response (default: the operation's first response). |
use_query()¶
def use_query(decorator: Callable[[Method], Method], handler: Callable[..., QueryHandler[CommandT, ResultT] | QueryHandler[CommandT, Awaitable[ResultT]]], *, query: Callable[[PayloadT], CommandT], status: int | None = None) -> Method: ...
A read operation: map the query parameters and call the resolved handler.
| Parameter | Type | Default | Description |
|---|---|---|---|
decorator |
Callable[[Method], Method] |
— | The operation decorator, e.g. get("/stats", response=StatsOut). |
handler |
Callable[..., QueryHandler[CommandT, ResultT] \| QueryHandler[CommandT, Awaitable[ResultT]]] |
— | A class with __call__(query) (sync or async), resolved from the container. |
query |
Callable[[PayloadT], CommandT] |
— | Maps the validated payload to the query; its parameter type is the query schema. |
status |
int \| None |
None |
Status code of the response (default: the operation's first response). |
CQRS building blocks¶
| Class | Arguments | Description |
|---|---|---|
Message |
— | Base for an application message. |
Command |
— | A request that changes state, handled by a use_case handler. |
Query |
— | A request that reads state, handled by a use_query handler. |
DomainEvent |
— | Base for a domain event; use a frozen dataclass subclass. |
EventBus |
tasks: TaskQueue |
A registry that delivers domain events after the current transaction commits. |
UnitOfWork |
*, using: str \| None = None, durable: bool = False |
Wrap a block in one transaction.atomic. |
Application plugins¶
| Class | Arguments | Description |
|---|---|---|
APIPlugin |
— | Base class for an application plugin. Override the parts you need. |
install()¶
Install plugins on api: error rules, middleware, then setup.
| Parameter | Type | Default | Description |
|---|---|---|---|
api |
NinjaAPI |
— | The NinjaAPI to configure. |
plugins |
Sequence[APIPlugin] |
— | Plugins applied in order. |
mount()¶
def mount(target: NinjaAPI | Router, routes: Mapping[str, type[Controller] | Mount], *, prefix: str = '', container: ContainerLike | None = None, scope: Scope | None = None, **options: Unpack[ControllerOptions]) -> dict[str, Router]: ...
Build and add a router per route; shared container, scope and options.
| Parameter | Type | Default | Description |
|---|---|---|---|
target |
NinjaAPI \| Router |
— | The NinjaAPI or Router to mount on. |
routes |
Mapping[str, type[Controller] \| Mount] |
— | {prefix: Controller} or {prefix: Mount(Controller, ...)}. |
prefix |
str |
'' |
Prepended to every route; also prefixes operation ids and URL names (versioning). |
container |
ContainerLike \| None |
None |
Shared container for every entry. |
scope |
Scope \| None |
None |
Shared scope for every entry. |
**options |
Unpack[ControllerOptions] |
— | ControllerOptions for every entry; errors= is also installed on a NinjaAPI. |
Mount¶
Per-route overrides for mount.
| Name | Type | Default | Description |
|---|---|---|---|
controller |
type[Controller] |
— | The controller class. |
container |
ContainerLike \| None |
None |
Container for this entry (default: the mount() container). |
scope |
Scope \| None |
None |
Scope for this entry (default: the mount() scope). |
options |
ControllerOptions |
field(default_factory=lambda: ControllerOptions()) |
ControllerOptions for this entry, over the mount() options. |
OperationInfo¶
Static description of an operation, built once per registration.
| Name | Type | Default | Description |
|---|---|---|---|
controller |
type[Controller] |
— | The controller class. |
method_name |
str |
— | The Python method implementing the operation. |
operation_id |
str |
— | The OpenAPI operation id. |
http_methods |
tuple[str, ...] |
— | HTTP methods of the operation. |
path |
str |
— | The path as declared on the router. |
is_async |
bool |
— | Whether the registered implementation is async. |
metadata |
tuple[object, ...] |
() |
Typed metadata from meta= (controller and operation), for permissions and hooks. |
database |
str \| None |
None |
Explicit operation/controller database alias, if configured. |
LoggingHook¶
Logs one structured record per operation call with its duration and outcome.
| Name | Type | Default | Description |
|---|---|---|---|
logger |
logging.Logger |
field(default_factory=lambda: logging.getLogger('ninja_devx')) |
Logger receiving one record per call. |
level |
int |
logging.INFO |
Log level of the record. |