A machine-readable [schema] describes what resources are available via the API, what their URLs are, how they are represented and what operations they support.
Deprecation notice:
REST framework's built-in support for generating OpenAPI schemas isdeprecated in favor of 3rd party packages that can provide thisfunctionality instead. The built-in support will be moved into a separatepackage and then subsequently retired over the next releases.
As a full-fledged replacement, we recommend thedrf-spectacular package.It has extensive support for generating OpenAPI 3 schemas fromREST framework APIs, with both automatic and customizable options available.For further information please refer toDocumenting your API.
API schemas are a useful tool that allow for a range of use cases, includinggenerating reference documentation, or driving dynamic client libraries thatcan interact with your API.
Django REST Framework provides support for automatic generation ofOpenAPI schemas.
Schema generation has several moving parts. It's worth having an overview:
SchemaGenerator is a top-level class that is responsible for walking your configured URL patterns, findingAPIView subclasses, enquiring for their schema representation, and compiling the final schema object.AutoSchema encapsulates all the details necessary for per-view schema introspection. Is attached to each view via theschema attribute. You subclassAutoSchema in order to customize your schema.generateschema management command allows you to generate a static schema offline.SchemaView to dynamically generate and serve your schema.settings.DEFAULT_SCHEMA_CLASS allows you to specify anAutoSchema subclass to serve as your project's default.The following sections explain more.
pip install pyyaml uritemplate inflectionpyyaml is used to generate schema into YAML-based OpenAPI format.uritemplate is used internally to get parameters in path.inflection is used to pluralize operations more appropriately in the list endpoints.generateschema management commandIf your schema is static, you can use thegenerateschema management command:
./manage.py generateschema --file openapi-schema.ymlOnce you've generated a schema in this way you can annotate it with anyadditional information that cannot be automatically inferred by the schemagenerator.
You might want to check your API schema into version control and update itwith each new release, or serve the API schema from your site's static media.
SchemaViewIf you require a dynamic schema, because foreign key choices depend on databasevalues, for example, you can route aSchemaView that will generate and serveyour schema on demand.
To route aSchemaView, use theget_schema_view() helper.
Inurls.py:
from rest_framework.schemas import get_schema_viewurlpatterns = [ # ... # Use the `get_schema_view()` helper to add a `SchemaView` to project URLs. # * `title` and `description` parameters are passed to `SchemaGenerator`. # * Provide view name for use with `reverse()`. path( "openapi", get_schema_view( title="Your Project", description="API for all things …", version="1.0.0" ), name="openapi-schema", ), # ...]get_schema_view()Theget_schema_view() helper takes the following keyword arguments:
title: May be used to provide a descriptive title for the schema definition.description: Longer descriptive text.version: The version of the API.url: May be used to pass a canonical base URL for the schema.
schema_view = get_schema_view( title='Server Monitoring API', url='https://www.example.org/api/')urlconf: A string representing the import path to the URL conf that you want to generate an API schema for. This defaults to the value of Django'sROOT_URLCONF setting.
schema_view = get_schema_view( title='Server Monitoring API', url='https://www.example.org/api/', urlconf='myproject.urls')patterns: List of url patterns to limit the schema introspection to. If you only want themyproject.api urls to be exposed in the schema:
schema_url_patterns = [ path('api/', include('myproject.api.urls')),]schema_view = get_schema_view( title='Server Monitoring API', url='https://www.example.org/api/', patterns=schema_url_patterns,)public: May be used to specify if schema should bypass views permissions. Default to Falsegenerator_class: May be used to specify aSchemaGenerator subclass to be passed to theSchemaView.
authentication_classes: May be used to specify the list of authentication classes that will apply to the schema endpoint. Defaults tosettings.DEFAULT_AUTHENTICATION_CLASSESpermission_classes: May be used to specify the list of permission classes that will apply to the schema endpoint. Defaults tosettings.DEFAULT_PERMISSION_CLASSES.renderer_classes: May be used to pass the set of renderer classes that can be used to render the API root endpoint.Schema-level customization
from rest_framework.schemas.openapi import SchemaGeneratorSchemaGenerator is a class that walks a list of routed URL patterns, requeststhe schema for each view and collates the resulting OpenAPI schema.
Typically you won't need to instantiateSchemaGenerator yourself, but you cando so like so:
generator = SchemaGenerator(title='Stock Prices API')Arguments:
titlerequired: The name of the API.description: Longer descriptive text.version: The version of the API. Defaults to0.1.0.url: The root URL of the API schema. This option is not required unless the schema is included under path prefix.patterns: A list of URLs to inspect when generating the schema. Defaults to the project's URL conf.urlconf: A URL conf module name to use when generating the schema. Defaults tosettings.ROOT_URLCONF.In order to customize the top-level schema, subclassrest_framework.schemas.openapi.SchemaGenerator and provide your subclassas an argument to thegenerateschema command orget_schema_view() helperfunction.
Returns a dictionary that represents the OpenAPI schema:
generator = SchemaGenerator(title='Stock Prices API')schema = generator.get_schema()Therequest argument is optional, and may be used if you want to applyper-user permissions to the resulting schema generation.
This is a good point to override if you want to customize the generateddictionary For example you might wish to add terms of service to thetop-levelinfo object:
class TOSSchemaGenerator(SchemaGenerator): def get_schema(self, *args, **kwargs): schema = super().get_schema(*args, **kwargs) schema["info"]["termsOfService"] = "https://example.com/tos.html" return schemaPer-View Customization
from rest_framework.schemas.openapi import AutoSchemaBy default, view introspection is performed by anAutoSchema instanceaccessible via theschema attribute onAPIView.
auto_schema = some_view.schemaAutoSchema provides the OpenAPI elements needed for each view, request methodand path:
components = auto_schema.get_components(...)operation = auto_schema.get_operation(...)In compiling the schema,SchemaGenerator callsget_components() andget_operation() for each view, allowed method, and path.
Note
The automatic introspection of components, and many operationparameters relies on the relevant attributes and methods ofGenericAPIView:get_serializer(),pagination_class,filter_backends,etc. For basicAPIView subclasses, default introspection is essentially limited tothe URL kwarg path parameters for this reason.
AutoSchema encapsulates the view introspection needed for schema generation.Because of this all the schema generation logic is kept in a single place,rather than being spread around the already extensive view, serializer andfield APIs.
Keeping with this pattern, try not to let schema logic leak into your ownviews, serializers, or fields when customizing the schema generation. You mightbe tempted to do something like this:
class CustomSchema(AutoSchema): """ AutoSchema subclass using schema_extra_info on the view. """ ...class CustomView(APIView): schema = CustomSchema() schema_extra_info = ... # some extra infoHere, theAutoSchema subclass goes looking forschema_extra_info on theview. This isOK (it doesn't actually hurt) but it means you'll end up withyour schema logic spread out in a number of different places.
Instead try to subclassAutoSchema such that theextra_info doesn't leakout into the view:
class BaseSchema(AutoSchema): """ AutoSchema subclass that knows how to use extra_info. """ ...class CustomSchema(BaseSchema): extra_info = ... # some extra infoclass CustomView(APIView): schema = CustomSchema()This style is slightly more verbose but maintains the encapsulation of theschema related code. It's morecohesive in theparlance. It'll keep therest of your API code more tidy.
If an option applies to many view classes, rather than creating a specificsubclass per-view, you may find it more convenient to allow specifying theoption as an__init__() kwarg to your baseAutoSchema subclass:
class CustomSchema(BaseSchema): def __init__(self, **kwargs): # store extra_info for later self.extra_info = kwargs.pop("extra_info") super().__init__(**kwargs)class CustomView(APIView): schema = CustomSchema(extra_info=...) # some extra infoThis saves you having to create a custom subclass per-view for a commonly used option.
Not allAutoSchema methods expose related__init__() kwargs, but those forthe more commonly needed options do.
AutoSchema methodsget_components()Generates the OpenAPI components that describe request and response bodies,deriving their properties from the serializer.
Returns a dictionary mapping the component name to the generatedrepresentation. By default this has just a single pair but you may overrideget_components() to return multiple pairs if your view uses multipleserializers.
get_component_name()Computes the component's name from the serializer.
You may see warnings if your API has duplicate component names. If so you can overrideget_component_name() or pass thecomponent_name__init__() kwarg (see below) to provide different names.
get_reference()Returns a reference to the serializer component. This may be useful if you overrideget_schema().
map_serializer()Maps serializers to their OpenAPI representations.
Most serializers should conform to the standard OpenAPIobject type, but you maywish to overridemap_serializer() in order to customize this or otherserializer-level fields.
map_field()Maps individual serializer fields to their schema representation. The base implementationwill handle the default fields that Django REST Framework provides.
ForSerializerMethodField instances, for which the schema is unknown, or custom field subclasses you should overridemap_field() to generate the correct schema:
class CustomSchema(AutoSchema): """Extension of ``AutoSchema`` to add support for custom field schemas.""" def map_field(self, field): # Handle SerializerMethodFields or custom fields here... # ... return super().map_field(field)Authors of third-party packages should aim to provide anAutoSchema subclass,and a mixin, overridingmap_field() so that users can easily generate schemasfor their custom fields.
get_tags()OpenAPI groups operations by tags. By default tags taken from the first pathsegment of the routed URL. For example, a URL like/users/{id}/ will generatethe tagusers.
You can pass an__init__() kwarg to manually specify tags (see below), oroverrideget_tags() to provide custom logic.
get_operation()Returns theOpenAPI operation object that describes theendpoint, including path and query parameters for pagination, filtering, and soon.
Together withget_components(), this is the main entry point to the viewintrospection.
get_operation_id()There must be a uniqueoperationid for each operation.By default theoperationId is deduced from the model name, serializer name orview name. The operationId looks like "listItems", "retrieveItem","updateItem", etc. TheoperationId is camelCase by convention.
get_operation_id_base()If you have several views with the same model name, you may see duplicateoperationIds.
In order to work around this, you can overrideget_operation_id_base() toprovide a different base for name part of the ID.
get_serializer()If the view has implementedget_serializer(), returns the result.
get_request_serializer()By default returnsget_serializer() but can be overridden todifferentiate between request and response objects.
get_response_serializer()By default returnsget_serializer() but can be overridden todifferentiate between request and response objects.
AutoSchema.__init__() kwargsAutoSchema provides a number of__init__() kwargs that can be used forcommon customizations, if the default generated values are not appropriate.
The available kwargs are:
tags: Specify a list of tags.component_name: Specify the component name.operation_id_base: Specify the resource-name part of operation IDs.You pass the kwargs when declaring theAutoSchema instance on your view:
class PetDetailView(generics.RetrieveUpdateDestroyAPIView): schema = AutoSchema( tags=['Pets'], component_name='Pet', operation_id_base='Pet', ) ...Assuming aPet model andPetSerializer serializer, the kwargs in thisexample are probably not needed. Often, though, you'll need to pass the kwargsif you have multiple view targeting the same model, or have multiple views withidentically named serializers.
If your views have related customizations that are needed frequently, you cancreate a baseAutoSchema subclass for your project that takes additional__init__() kwargs to save subclassingAutoSchema for each view.