Схема¶
Машиночитаемая [схема] описывает, какие ресурсы доступны через API, каковы их URL, как они представлены и какие операции они поддерживают.
‒ Heroku, JSON Schema for the Heroku Platform API
Схемы API - это полезный инструмент, который позволяет использовать их в различных случаях, включая создание справочной документации или создание динамических клиентских библиотек, которые могут взаимодействовать с вашим API.
Django REST Framework обеспечивает поддержку автоматической генерации схем OpenAPI.
Обзор¶
Генерация схемы состоит из нескольких движущихся частей. Стоит сделать обзор:
SchemaGenerator
- это класс верхнего уровня, который отвечает за прохождение по шаблонам URL, поиск подклассовAPIView
, запрос их представления схемы и компиляцию конечного объекта схемы.AutoSchema
инкапсулирует все детали, необходимые для интроспекции схемы каждого представления. Прикрепляется к каждому представлению с помощью атрибутаschema
. Вы подклассифицируетеAutoSchema
для того, чтобы настроить свою схему.Команда управления
generateschema
позволяет генерировать статическую схему в автономном режиме.В качестве альтернативы, вы можете направить
SchemaView
для динамической генерации и обслуживания вашей схемы.settings.DEFAULT_SCHEMA_CLASS
позволяет вам указать подклассAutoSchema
, который будет использоваться по умолчанию в вашем проекте.
В следующих разделах рассказывается подробнее.
Генерация схемы OpenAPI¶
Установите зависимости¶
pip install pyyaml uritemplate
pyyaml
используется для генерации схемы в формат OpenAPI на основе YAML.uritemplate
используется внутренне для получения параметров в пути.
Генерация статической схемы с помощью команды управления generateschema
¶
Если ваша схема статична, вы можете использовать команду управления generateschema
:
./manage.py generateschema --file openapi-schema.yml
После создания схемы таким образом вы можете аннотировать ее любой дополнительной информацией, которая не может быть автоматически выведена генератором схемы.
Вы можете зарегистрировать схему API в системе контроля версий и обновлять ее с каждым новым релизом, или использовать схему API из статического медиа вашего сайта.
Генерация динамической схемы с помощью SchemaView
¶
Если вам требуется динамическая схема, например, потому что выбор внешнего ключа зависит от значений базы данных, вы можете направить SchemaView
, который будет генерировать и обслуживать вашу схему по требованию.
Для маршрутизации SchemaView
, используйте помощник get_schema_view()
.
В urls.py
:
from rest_framework.schemas import get_schema_view
urlpatterns = [
# ...
# 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()
¶
Помощник get_schema_view()
принимает следующие аргументы в виде ключевых слов:
title
: Может использоваться для предоставления описательного заголовка для определения схемы.<<< 0 >>**: Более длинный описательный текст.
version
: Версия API.url
: Может использоваться для передачи канонического базового URL для схемы.schema_view = get_schema_view( title='Server Monitoring API', url='https://www.example.org/api/' )
urlconf
Строка, представляющая путь импорта к URL conf, который вам нужендля создания схемы API. По умолчанию это значение равно значению параметра Django
ROOT_URLCONF
.
schema_view = get_schema_view( title='Server Monitoring API', url='https://www.example.org/api/', urlconf='myproject.urls' )
patterns
: Список шаблонов url для ограничения интроспекции схемы. Если вы хотите, чтобы толькоmyproject.api
урлы были отображены в схеме: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, )
generator_class
: Может использоваться для указанияSchemaGenerator
подкласса, который будет передан вSchemaView
.authentication_classes
: Может использоваться для указания списка классов аутентификации, которые будут применяться к конечной точке схемы. По умолчаниюsettings.DEFAULT_AUTHENTICATION_CLASSES
permission_classes
: Может использоваться для указания списка классов разрешений, которые будут применяться к конечной точке схемы. По умолчаниюsettings.DEFAULT_PERMISSION_CLASSES
.renderer_classes
: Может использоваться для передачи набора классов рендеринга, которые могут быть использованы для рендеринга корневой конечной точки API.
SchemaGenerator¶
Настройка на уровне схемы
from rest_framework.schemas.openapi import SchemaGenerator
SchemaGenerator
- это класс, который просматривает список шаблонов URL, запрашивает схему для каждого представления и собирает полученную схему OpenAPI.
Обычно вам не нужно самостоятельно инстанцировать SchemaGenerator
, но вы можете сделать это следующим образом:
generator = SchemaGenerator(title='Stock Prices API')
Аргументы:
title
обязательно : Имя API.<<< 0 >>**: Более длинный описательный текст.
version
: Версия API. По умолчанию0.1.0
.url
: Корневой URL схемы API. Этот параметр не требуется, если схема не включена в префикс path.patterns
: Список URL-адресов для проверки при генерации схемы. По умолчанию используется URL conf проекта.urlconf
: Имя модуля URL conf для использования при генерации схемы. По умолчаниюsettings.ROOT_URLCONF
.
Чтобы настроить схему верхнего уровня, создайте подкласс rest_framework.schemas.openapi.SchemaGenerator
и предоставьте свой подкласс в качестве аргумента команде generateschema
или вспомогательной функции get_schema_view()
.
get_schema(self, request)¶
Возвращает словарь, представляющий схему OpenAPI:
generator = SchemaGenerator(title='Stock Prices API')
schema = generator.get_schema()
Аргумент request
является необязательным и может быть использован, если вы хотите применить разрешения для каждого пользователя к результирующей генерации схемы.
Например, вы можете добавить условия обслуживания к top-level ``info:doc:` object <https://swagger.io/specification/#infoObject>`** :
class TOSSchemaGenerator(SchemaGenerator):
def get_schema(self, *args, **kwargs):
schema = super().get_schema(*args, **kwargs)
schema["info"]["termsOfService"] = "https://example.com/tos.html"
return schema
AutoSchema¶
Настройка для каждого вида
from rest_framework.schemas.openapi import AutoSchema
По умолчанию интроспекция представления выполняется экземпляром AutoSchema
, доступным через атрибут schema
на APIView
.
auto_schema = some_view.schema
AutoSchema
предоставляет элементы OpenAPI, необходимые для каждого представления, метода запроса и пути:
Список OpenAPI components. В терминах DRF это отображения сериализаторов, которые описывают тела запросов и ответов.
Соответствующий OpenAPI operation object, описывающий конечную точку, включая путь и параметры запроса для пагинации, фильтрации и так далее.
components = auto_schema.get_components(...)
operation = auto_schema.get_operation(...)
При компиляции схемы SchemaGenerator
вызывает get_components()
и get_operation()
для каждого представления, разрешенного метода и пути.
Примечание: Автоматическая интроспекция компонентов и многих параметров операций опирается на соответствующие атрибуты и методы GenericAPIView
: get_serializer()
, pagination_class
, filter_backends
и т.д. По этой причине для основных подклассов APIView
по умолчанию интроспекция по существу ограничена параметрами пути URL kwarg.
AutoSchema
инкапсулирует интроспекцию представления, необходимую для генерации схемы. Благодаря этому вся логика генерации схемы хранится в одном месте, а не разбросана по и без того обширным API представления, сериализатора и поля.
Следуя этому шаблону, старайтесь не допускать утечки логики схемы в ваши собственные представления, сериализаторы или поля при настройке генерации схемы. У вас может возникнуть соблазн сделать что-то вроде этого:
class CustomSchema(AutoSchema):
"""
AutoSchema subclass using schema_extra_info on the view.
"""
...
class CustomView(APIView):
schema = CustomSchema()
schema_extra_info = ... some extra info ...
Здесь подкласс AutoSchema
ищет schema_extra_info
в представлении. Это OK (на самом деле это не больно), но это означает, что в итоге вы получите логику схемы, разбросанную по разным местам.
Вместо этого попробуйте подкласс AutoSchema
, чтобы extra_info
не просачивался в представление:
class BaseSchema(AutoSchema):
"""
AutoSchema subclass that knows how to use extra_info.
"""
...
class CustomSchema(BaseSchema):
extra_info = ... some extra info ...
class CustomView(APIView):
schema = CustomSchema()
Этот стиль немного более многословен, но сохраняет инкапсуляцию кода, связанного со схемой. Он более целостный в парламенте. Это сделает остальной код вашего API более аккуратным.
Если опция применяется ко многим классам представлений, вместо того, чтобы создавать отдельный подкласс для каждого представления, вам может показаться более удобным разрешить указывать опцию как __init__()
kwarg к вашему базовому AutoSchema
подклассу:
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 info ...
)
Это избавит вас от необходимости создавать собственный подкласс для каждого вида для часто используемой опции.
Не все методы AutoSchema
раскрывают связанные с ними __init__()
kwargs, но те, которые предназначены для наиболее часто используемых опций, раскрывают.
AutoSchema
методы¶
get_components()
¶
Генерирует компоненты OpenAPI, описывающие тела запросов и ответов, получая их свойства от сериализатора.
Возвращает словарь, отображающий имя компонента на сгенерированное представление. По умолчанию он содержит только одну пару, но вы можете переопределить get_components()
, чтобы вернуть несколько пар, если ваше представление использует несколько сериализаторов.
get_component_name()
¶
Вычисляет имя компонента из сериализатора.
Вы можете увидеть предупреждения, если в вашем API есть дублирующиеся имена компонентов. В этом случае вы можете переопределить get_component_name()
или передать кваргу component_name
__init__()
(см. ниже), чтобы обеспечить разные имена.
map_serializer()
¶
Сопоставляет сериализаторы с их представлениями OpenAPI.
Большинство сериализаторов должны соответствовать стандартному типу OpenAPI object
, но вы можете захотеть переопределить map_serializer()
, чтобы настроить это или другие поля на уровне сериализатора.
map_field()
¶
Сопоставляет отдельные поля сериализатора с их схемным представлением. Базовая реализация будет работать с полями по умолчанию, которые предоставляет Django REST Framework.
Для экземпляров SerializerMethodField
, для которых схема неизвестна, или подклассов пользовательских полей следует переопределить map_field()
, чтобы сгенерировать правильную схему:
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)
Авторы сторонних пакетов должны стремиться предоставить подкласс AutoSchema
и миксин, переопределяющий map_field()
, чтобы пользователи могли легко генерировать схемы для своих пользовательских полей.
get_tags()
¶
OpenAPI группирует операции по тегам. По умолчанию теги берутся из первого сегмента пути маршрутизируемого URL. Например, URL типа /users/{id}/
будет генерировать тег users
.
Вы можете передать __init__()
kwarg, чтобы вручную указать теги (см. ниже), или переопределить get_tags()
, чтобы обеспечить пользовательскую логику.
get_operation()
¶
Возвращает OpenAPI operation object, описывающий конечную точку, включая путь и параметры запроса для пагинации, фильтрации и так далее.
Вместе с get_components()
, это основная точка входа в интроспекцию вида.
get_operation_id()
¶
Для каждой операции должен быть уникальный operationid. По умолчанию operationId
выводится из имени модели, имени сериализатора или имени представления. OperationId выглядит как «listItems», «retrieveItem», «updateItem» и т.д. По соглашению operationId
- это camelCase.
get_operation_id_base()
¶
Если у вас есть несколько представлений с одинаковым именем модели, вы можете увидеть дублирующиеся идентификаторы операций.
Чтобы обойти это, вы можете переопределить get_operation_id_base()
, чтобы обеспечить другую базу для именной части ID.
get_serializer()
¶
Если представление реализовало get_serializer()
, возвращает результат.
get_request_serializer()
¶
По умолчанию возвращает get_serializer()
, но может быть переопределено для различения объектов запроса и ответа.
get_response_serializer()
¶
По умолчанию возвращает get_serializer()
, но может быть переопределено для различения объектов запроса и ответа.
AutoSchema.__init__()
kwargs¶
AutoSchema
предоставляет ряд __init__()
kwargs, которые могут быть использованы для общих настроек, если сгенерированные по умолчанию значения не подходят.
Доступные значения kwargs следующие:
tags
: Укажите список тегов.component_name
: Укажите имя компонента.operation_id_base
: Укажите часть имени ресурса в идентификаторах операций.
Вы передаете kwargs при объявлении экземпляра AutoSchema
в вашем представлении:
class PetDetailView(generics.RetrieveUpdateDestroyAPIView):
schema = AutoSchema(
tags=['Pets'],
component_name='Pet',
operation_id_base='Pet',
)
...
Если предположить, что модель Pet
и сериализатор PetSerializer
, то kwargs в этом примере, скорее всего, не нужны. Однако часто kwargs необходимо передавать, если у вас есть несколько представлений, нацеленных на одну и ту же модель, или несколько представлений с одинаковыми именами сериализаторов.
Если ваши представления имеют связанные настройки, которые требуются часто, вы можете создать базовый AutoSchema
подкласс для вашего проекта, который принимает дополнительные __init__()
kwargs для экономии подклассификации AutoSchema
для каждого представления.