Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 241 additions & 50 deletions docs/api-guide/schemas.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ API schemas are a useful tool that allow for a range of use cases, including
generating reference documentation, or driving dynamic client libraries that
can interact with your API.

## Representing schemas internally
## Install Core API

You'll need to install the `coreapi` package in order to add schema support
for REST framework.

pip install coreapi

## Internal schema representation

REST framework uses [Core API][coreapi] in order to model schema information in
a format-independent representation. This information can then be rendered
Expand Down Expand Up @@ -68,9 +75,32 @@ has to be rendered into the actual bytes that are used in the response.
REST framework includes a renderer class for handling this media type, which
is available as `renderers.CoreJSONRenderer`.

### Alternate schema formats

Other schema formats such as [Open API][open-api] ("Swagger"),
[JSON HyperSchema][json-hyperschema], or [API Blueprint][api-blueprint] can
also be supported by implementing a custom renderer class.
[JSON HyperSchema][json-hyperschema], or [API Blueprint][api-blueprint] can also
be supported by implementing a custom renderer class that handles converting a
`Document` instance into a bytestring representation.

If there is a Core API codec package that supports encoding into the format you
want to use then implementing the renderer class can be done by using the codec.

#### Example

For example, the `openapi_codec` package provides support for encoding or decoding
to the Open API ("Swagger") format:

from rest_framework import renderers
from openapi_codec import OpenAPICodec

class SwaggerRenderer(renderers.BaseRenderer):
media_type = 'application/openapi+json'
format = 'swagger'

def render(self, data, media_type=None, renderer_context=None):
codec = OpenAPICodec()
return codec.dump(data)


## Schemas vs Hypermedia

Expand All @@ -91,16 +121,125 @@ is planned for a future version.

---

# Adding a schema
# Creating a schema

You'll need to install the `coreapi` package in order to add schema support
for REST framework.
REST framework includes functionality for auto-generating a schema,
or allows you to specify one explicitly.

pip install coreapi
## Manual Schema Specification

REST framework includes functionality for auto-generating a schema,
or allows you to specify one explicitly. There are a few different ways to
add a schema to your API, depending on exactly what you need.
To manually specify a schema you create a Core API `Document`, similar to the
example above.

schema = coreapi.Document(
title='Flight Search API',
content={
...
}
)


## Automatic Schema Generation

Automatic schema generation is provided by the `SchemaGenerator` class.

`SchemaGenerator` processes a list of routed URL patterns and compiles the
appropriately structured Core API Document.

Basic usage is just to provide the title for your schema and call
`get_schema()`:

generator = schemas.SchemaGenerator(title='Flight Search API')
schema = generator.get_schema()

### Per-View Schema Customisation

By default, view introspection is performed by an `AutoSchema` instance
accessible via the `schema` attribute on `APIView`. This provides the
appropriate Core API `Link` object for the view, request method and path:

auto_schema = view.schema
coreapi_link = auto_schema.get_link(...)

(In compiling the schema, `SchemaGenerator` calls `view.schema.get_link()` for
each view, allowed method and path.)

To customise the `Link` generation you may:

* Instantiate `AutoSchema` on your view with the `manual_fields` kwarg:

from rest_framework.views import APIView
from rest_framework.schemas import AutoSchema

class CustomView(APIView):
...
schema = AutoSchema(
manual_fields=[
coreapi.Field("extra_field", ...),
]
)

This allows extension for the most common case without subclassing.

* Provide an `AutoSchema` subclass with more complex customisation:

from rest_framework.views import APIView
from rest_framework.schemas import AutoSchema

class CustomSchema(AutoSchema):
def get_link(self, path, method, base_url):
# Implement custom introspection here (or in other sub-methods)
...

class CustomView(APIView):
...
schema = CustomSchema()

This provides complete control over view introspection.

* Instantiate `ManualSchema` on your view, providing the Core API `Fields` for
the view explicitly:

from rest_framework.views import APIView
from rest_framework.schemas import ManualSchema

class CustomView(APIView):
...
schema = ManualSchema(fields=[
coreapi.Field(
"first_field",
required=True,
location="path",
schema=coreschema.String()
),
coreapi.Field(
"second_field",
required=True,
location="path",
schema=coreschema.String()
),
])

This allows manually specifying the schema for some views whilst maintaining
automatic generation elsewhere.

* You can exclude a view from the schema entirely by setting `schema` to `None`:

class CustomView(APIView):
...
schema = None # Will not appear in schema

---

**Note**: For full details on `SchemaGenerator` plus the `AutoSchema` and
`ManualSchema` descriptors see the [API Reference below](#api-reference).
Comment on lines +169 to +235
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These examples and the surrounding text rely on AutoSchema/ManualSchema being available on rest_framework.schemas and on APIView.schema existing (auto_schema = view.schema). In this repository there is no AutoSchema/ManualSchema class and APIView only has exclude_from_schema; schema generation is handled directly by SchemaGenerator/EndpointInspector in rest_framework/schemas.py. The per-view customization section should be rewritten to match the actual implementation, or the corresponding code refactor needs to be included before merging these docs.

Suggested change
* Instantiate `AutoSchema` on your view with the `manual_fields` kwarg:
from rest_framework.views import APIView
from rest_framework.schemas import AutoSchema
class CustomView(APIView):
...
schema = AutoSchema(
manual_fields=[
coreapi.Field("extra_field", ...),
]
)
This allows extension for the most common case without subclassing.
* Provide an `AutoSchema` subclass with more complex customisation:
from rest_framework.views import APIView
from rest_framework.schemas import AutoSchema
class CustomSchema(AutoSchema):
def get_link(self, path, method, base_url):
# Implement custom introspection here (or in other sub-methods)
...
class CustomView(APIView):
...
schema = CustomSchema()
This provides complete control over view introspection.
* Instantiate `ManualSchema` on your view, providing the Core API `Fields` for
the view explicitly:
from rest_framework.views import APIView
from rest_framework.schemas import ManualSchema
class CustomView(APIView):
...
schema = ManualSchema(fields=[
coreapi.Field(
"first_field",
required=True,
location="path",
schema=coreschema.String()
),
coreapi.Field(
"second_field",
required=True,
location="path",
schema=coreschema.String()
),
])
This allows manually specifying the schema for some views whilst maintaining
automatic generation elsewhere.
* You can exclude a view from the schema entirely by setting `schema` to `None`:
class CustomView(APIView):
...
schema = None # Will not appear in schema
---
**Note**: For full details on `SchemaGenerator` plus the `AutoSchema` and
`ManualSchema` descriptors see the [API Reference below](#api-reference).
* Provide custom schema introspection by subclassing the core schema classes:
from rest_framework.schemas import SchemaGenerator, EndpointInspector
class CustomEndpointInspector(EndpointInspector):
def get_links(self, request=None):
# Implement custom introspection here (or in other sub-methods)
...
class CustomSchemaGenerator(SchemaGenerator):
endpoint_inspectors = [CustomEndpointInspector]
This allows you to tailor how views are inspected and how `Link` instances
are generated, without modifying individual views.
* You can exclude a view from the schema entirely by setting
`exclude_from_schema` to `True` on the view:
from rest_framework.views import APIView
class CustomView(APIView):
...
exclude_from_schema = True # Will not appear in schema
---
**Note**: For full details on `SchemaGenerator` and `EndpointInspector` see the
[API Reference below](#api-reference).

Copilot uses AI. Check for mistakes.

---

# Adding a schema view

There are a few different ways to add a schema view to your API, depending on
exactly what you need.

## The get_schema_view shortcut

Expand Down Expand Up @@ -304,7 +443,7 @@ An `APIView`, with an explicit method docstring.
usernames = [user.username for user in User.objects.all()]
return Response(usernames)

A `ViewSet`, with an explict action docstring.
A `ViewSet`, with an explicit action docstring.

class ListUsernames(ViewSet):
def list(self, request):
Expand Down Expand Up @@ -342,38 +481,12 @@ A generic viewset with sections in the class docstring, using multi-line style.

---

# Alternate schema formats

In order to support an alternate schema format, you need to implement a custom renderer
class that handles converting a `Document` instance into a bytestring representation.

If there is a Core API codec package that supports encoding into the format you
want to use then implementing the renderer class can be done by using the codec.

## Example

For example, the `openapi_codec` package provides support for encoding or decoding
to the Open API ("Swagger") format:

from rest_framework import renderers
from openapi_codec import OpenAPICodec

class SwaggerRenderer(renderers.BaseRenderer):
media_type = 'application/openapi+json'
format = 'swagger'

def render(self, data, media_type=None, renderer_context=None):
codec = OpenAPICodec()
return codec.dump(data)

---

# API Reference

## SchemaGenerator

A class that deals with introspecting your API views, which can be used to
generate a schema.
A class that walks a list of routed URL patterns, requests the schema for each view,
and collates the resulting CoreAPI Document.

Typically you'll instantiate `SchemaGenerator` with a single argument, like so:

Expand Down Expand Up @@ -406,38 +519,116 @@ Return a nested dictionary containing all the links that should be included in t
This is a good point to override if you want to modify the resulting structure of the generated schema,
as you can build a new dictionary with a different layout.

### get_link(self, path, method, view)

## AutoSchema

A class that deals with introspection of individual views for schema generation.

`AutoSchema` is attached to `APIView` via the `schema` attribute.

The `AutoSchema` constructor takes a single keyword argument `manual_fields`.

**`manual_fields`**: a `list` of `coreapi.Field` instances that will be added to
the generated fields. Generated fields with a matching `name` will be overwritten.

class CustomView(APIView):
schema = AutoSchema(manual_fields=[
coreapi.Field(
"my_extra_field",
required=True,
location="path",
schema=coreschema.String()
),
])

For more advanced customisation subclass `AutoSchema` to customise schema generation.

class CustomViewSchema(AutoSchema):
"""
Overrides `get_link()` to provide Custom Behavior X
"""

def get_link(self, path, method, base_url):
link = super().get_link(path, method, base_url)
# Do something to customize link here...
return link

class MyView(APIView):
schema = CustomViewSchema()

The following methods are available to override.

### get_link(self, path, method, base_url)

Returns a `coreapi.Link` instance corresponding to the given view.

This is the main entry point.
You can override this if you need to provide custom behaviors for particular views.

### get_description(self, path, method, view)
### get_description(self, path, method)

Returns a string to use as the link description. By default this is based on the
view docstring as described in the "Schemas as Documentation" section above.

### get_encoding(self, path, method, view)
### get_encoding(self, path, method)

Returns a string to indicate the encoding for any request body, when interacting
with the given view. Eg. `'application/json'`. May return a blank string for views
that do not expect a request body.

### get_path_fields(self, path, method, view):
### get_path_fields(self, path, method)

Return a list of `coreapi.Field` instances. One for each path parameter in the URL.

### get_serializer_fields(self, path, method)

Return a list of `coreapi.Field` instances. One for each field in the serializer class used by the view.

### get_pagination_fields(self, path, method)

Return a list of `coreapi.Field` instances, as returned by the `get_schema_fields()` method on any pagination class used by the view.

### get_filter_fields(self, path, method)

Return a list of `coreapi.Field` instances, as returned by the `get_schema_fields()` method of any filter classes used by the view.

### get_manual_fields(self, path, method)

Returns the list of `coreapi.Field` instances provided as `manual_fields` when
the `AutoSchema` was instantiated. Override to vary manual fields by path or method.

### update_fields(fields, update_with)

Static method. Merges two lists of `coreapi.Field` instances, overwriting on
`Field.name`. Used internally to apply `manual_fields` on top of generated fields.
Comment on lines +523 to +603
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API reference documents an AutoSchema class and method signatures like get_link(self, path, method, base_url) / get_description(self, path, method) etc, but the current implementation in rest_framework/schemas.py defines these methods on SchemaGenerator with a view parameter (get_link(self, path, method, view), get_description(self, path, method, view), ...). Please update the reference section to reflect the actual public API (or include the underlying code changes that introduce AutoSchema and the updated signatures).

Copilot uses AI. Check for mistakes.

Return a list of `coreapi.Link()` instances. One for each path parameter in the URL.

### get_serializer_fields(self, path, method, view)
## ManualSchema

Return a list of `coreapi.Link()` instances. One for each field in the serializer class used by the view.
Allows manually providing a list of `coreapi.Field` instances for the schema,
plus an optional description.

### get_pagination_fields(self, path, method, view
class MyView(APIView):
schema = ManualSchema(fields=[
coreapi.Field(
"first_field",
required=True,
location="path",
schema=coreschema.String()
),
coreapi.Field(
"second_field",
required=True,
location="path",
schema=coreschema.String()
),
])

Return a list of `coreapi.Link()` instances, as returned by the `get_schema_fields()` method on any pagination class used by the view.
The `ManualSchema` constructor takes two arguments:

### get_filter_fields(self, path, method, view)
**`fields`**: A list of `coreapi.Field` instances. Required.

Return a list of `coreapi.Link()` instances, as returned by the `get_schema_fields()` method of any filter classes used by the view.
**`description`**: A string description. Optional.

---

Expand Down
22 changes: 22 additions & 0 deletions docs/api-guide/views.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,28 @@ The available decorators are:

Each of these decorators takes a single argument which must be a list or tuple of classes.


## View schema decorator

To override the default schema generation for function based views you may use
the `@schema` decorator. This must come *after* (below) the `@api_view`
decorator. For example:

from rest_framework.decorators import api_view, schema
from rest_framework.schemas import AutoSchema

class CustomAutoSchema(AutoSchema):
def get_link(self, path, method, base_url):
# override view introspection here...

@api_view(['GET'])
@schema(CustomAutoSchema())
def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})

This decorator takes a single `AutoSchema` instance, an `AutoSchema` subclass
Comment on lines +190 to +206
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs introduce an @schema decorator for function-based views, but rest_framework.decorators in this repo does not define schema (only api_view, policy decorators, and route decorators). As written, from rest_framework.decorators import api_view, schema will fail; either document the existing API (e.g., exclude_from_schema) or land the actual schema decorator implementation first and then document it.

Suggested change
To override the default schema generation for function based views you may use
the `@schema` decorator. This must come *after* (below) the `@api_view`
decorator. For example:
from rest_framework.decorators import api_view, schema
from rest_framework.schemas import AutoSchema
class CustomAutoSchema(AutoSchema):
def get_link(self, path, method, base_url):
# override view introspection here...
@api_view(['GET'])
@schema(CustomAutoSchema())
def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})
This decorator takes a single `AutoSchema` instance, an `AutoSchema` subclass
To override the default schema generation for function based views you may set
the `schema` attribute on the view after it has been created. For example:
from rest_framework.decorators import api_view
from rest_framework.schemas import AutoSchema
class CustomAutoSchema(AutoSchema):
def get_link(self, path, method, base_url):
# override view introspection here...
...
@api_view(['GET'])
def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})
view.schema = CustomAutoSchema()
This attribute should be set to an `AutoSchema` instance, an `AutoSchema` subclass

Copilot uses AI. Check for mistakes.
instance or `ManualSchema` instance as described in the [Schemas documentation][schemas].

[cite]: http://reinout.vanrees.org/weblog/2011/08/24/class-based-views-usage.html
[cite2]: http://www.boredomandlaziness.org/2012/05/djangos-cbvs-are-not-mistake-but.html
[settings]: settings.md
Expand Down