Skip to content

OpenAPI

enable_openapi

enable_openapi() -> None

Set :class:ServiceAutoSchema as the schema on every library view class.

Call once from AppConfig.ready() (or anywhere after Django apps are loaded) to make drf-spectacular see ServiceSpec request bodies, response bodies, success statuses, and 422 contracts on:

  • ServiceCreateView, ServiceUpdateView, ServiceDeleteView
  • SelectorListView, SelectorRetrieveView
  • ServiceViewSet, SelectorViewSet

The function-local imports keep drf-spectacular an optional dependency: importing :mod:rest_framework_services.openapi does not require it, and only this call brings in the schema-generator code.

User subclasses inherit schema = ServiceAutoSchema() automatically; classes that set schema = ... explicitly keep their own choice.

ServiceAutoSchema

Bases: AutoSchema

AutoSchema that derives its request / response from a ServiceSpec.

For mutation surfaces (standalone Service*View classes, the ServiceViewSet action mixins, and @service_action):

  • Request body is derived from spec.input_serializer (a bare dataclass is auto-wrapped in :class:DataclassSerializer).
  • Response body for the success status is derived from spec.output_selector_spec.output_serializer (or rendered as a no-content response when unset and the action's default status is 204).
  • A 422 response documenting :class:ServiceErrorSerializer is attached when the operation can surface a ServiceError. By default that is gated on whether the operation validates input (spec.input_serializer is not None), so a no-input mutation (e.g. a plain delete) carries no spurious 422; spec.document_service_error forces the decision either way.
  • Partial-update actions instantiate the request serializer with partial=True so optional-on-PATCH semantics show up correctly. spec.partial overrides the action-derived flag with the same precedence the runtime dispatch applies: partial=True documents a partial body on any verb, partial=False keeps the full-update schema (required fields intact) even under PATCH.

Read surfaces (Selector*View and the read-side action mixins) lean on the base AutoSchema for their body: the output_serializer is already wired through get_serializer_class() and that's what drf-spectacular reads natively. The one addition is :meth:_get_filter_parameters, which contributes the query parameters for a SelectorSpec.filter_set — the FilterSet the selector carries on the spec instead of on the view — so moving a FilterSet from a view-level filterset_class + DjangoFilterBackend onto spec.filter_set leaves the generated OpenAPI unchanged.

User-supplied @extend_schema annotations always win — they're consulted upstream of get_request_serializer / get_response_serializers, and @extend_schema(parameters=...) overrides merge over the filter parameters exactly as they do for a view-level FilterSet.

ServiceErrorSerializer

Bases: Serializer

Single-field detail serializer that mirrors _ServiceAPIException.

Used by :class:ServiceAutoSchema to attach a 422 response to every spec-driven mutation in the generated OpenAPI document. It is only used for schema generation; runtime 422 bodies are produced by DRF's exception handler from :class:~rest_framework_services.views.mutation.map_service_error._ServiceAPIException.