OpenAPI / Swagger schemas¶
djangorestframework-services ships an opt-in
drf-spectacular integration that
makes the generated OpenAPI document line up with what your ServiceSpec
actually does — without scattering @extend_schema annotations across
every view.
Install¶
Wire it up¶
Two settings, one call:
# settings.py
REST_FRAMEWORK = {
# Required for spectacular to inspect every view, including plain
# ``GenericViewSet`` classes that use ``@service_action``.
"DEFAULT_SCHEMA_CLASS": (
"rest_framework_services.openapi.service_auto_schema.ServiceAutoSchema"
),
# ... your usual REST_FRAMEWORK config
}
# myapp/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = "myapp"
def ready(self) -> None:
from rest_framework_services.openapi import enable_openapi
enable_openapi()
enable_openapi() attaches ServiceAutoSchema to every library view class
(ServiceCreateView, ServiceUpdateView, ServiceDeleteView,
SelectorListView, SelectorRetrieveView, ServiceViewSet,
SelectorViewSet). The DEFAULT_SCHEMA_CLASS setting covers anything
else.
What you get for free¶
| Surface | Request body | Success response | 422 contract |
|---|---|---|---|
ServiceCreateView |
spec.input_serializer ✓ |
spec.output_serializer ✓ |
✓ |
ServiceUpdateView |
spec.input_serializer ✓ |
spec.output_serializer ✓ |
✓ |
ServiceDeleteView |
spec.input_serializer ✓ |
spec.output_serializer ✓ |
✓ |
ServiceViewSet["create"] |
spec.input_serializer ✓ |
spec.output_serializer ✓ |
✓ |
ServiceViewSet["update"] |
spec.input_serializer ✓ |
spec.output_serializer ✓ |
✓ |
ServiceViewSet["partial_update"] |
spec.input_serializer (partial) ✓ |
spec.output_serializer ✓ |
✓ |
ServiceViewSet["destroy"] |
spec.input_serializer ✓ |
spec.output_serializer ✓ |
✓ |
@service_action |
spec.input_serializer ✓ |
spec.output_serializer ✓ |
✓ |
SelectorListView / ["list"] |
n/a | spec.output_serializer ✓ |
n/a |
SelectorRetrieveView / ["retrieve"] |
n/a | spec.output_serializer ✓ |
n/a |
Bare dataclass input_serializer¶
The runtime auto-wraps a bare @dataclass type in a DataclassSerializer.
The schema generator does the same — your dataclass shows up as a typed
component, not a plain object.
Success status codes¶
Default to the action's HTTP code (201 / 200 / 204) unless
spec.success_status overrides it. The schema picks up whichever value
the runtime would return.
422 ServiceError responses¶
ServiceAutoSchema attaches a 422 response with a single detail
field to every spec-driven mutation, documenting the contract that
ServiceError produces at runtime. The component is exposed as
rest_framework_services.openapi.ServiceErrorSerializer if you want to
re-use it elsewhere.
Override per view¶
@extend_schema annotations always win. Use them for the rare case
where the spec doesn't capture the full contract:
from drf_spectacular.utils import extend_schema, OpenApiResponse
class _MyViewSet(ServiceViewSet):
action_specs = {"create": ServiceSpec(...)}
@extend_schema(responses={201: MyCustomSerializer, 409: OpenApiResponse(...)})
def create(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)
What's not covered¶
- Field-level shapes for 400
ValidationErrorbodies (DRF doesn't have a great way to express this, and spectacular's defaults are passable). - Auto-generated named components for
ChangeResultand similar internal value types — they render inline. - A dedicated
OpenApiSerializerExtensionforDataclassSerializergiving named components in#/components/schemas/...instead of inline anonymous schemas. Deferred; spectacular's default rendering is usable.