Schemas

Машиночитаемая [схема] описывает, какие ресурсы доступны через API, каковы их URL, как они представлены и какие операции они поддерживают.


Уведомление о сокращении:

Встроенная в DRF поддержка генерации схем OpenAPI утрачена в пользу сторонних пакетов, которые могут предоставить эту функциональность вместо нее. Встроенная поддержка будет перенесена в отдельный пакет, а затем в последующих релизах будет удалена.

В качестве полноценной замены мы рекомендуем пакет drf-spectacular. Он обладает широкой поддержкой генерации схем OpenAPI 3 из API DRF, причем доступны как автоматические, так и настраиваемые опции. За дополнительной информацией обращайтесь к Documenting your API.


Схемы API - это полезный инструмент, который позволяет использовать их в различных случаях, включая создание справочной документации или создание динамических клиентских библиотек, которые могут взаимодействовать с вашим API.

DRF обеспечивает поддержку автоматической генерации схем OpenAPI.

Обзор

Генерация схемы состоит из нескольких движущихся частей. Стоит сделать обзор:

  • SchemaGenerator - это класс верхнего уровня, который отвечает за поиск шаблонов URL, нахождение подклассов APIView, запрос их представления схемы и компиляцию конечного объекта схемы.

  • AutoSchema инкапсулирует все детали, необходимые для интроспекции схемы для каждого представления. Прикрепляется к каждому представлению через атрибут schema. Вы подклассифицируете AutoSchema для того, чтобы настроить свою схему.

  • Команда управления generateschema позволяет вам генерировать статическую схему в автономном режиме.

  • Альтернативно, вы можете направить SchemaView для динамической генерации и обслуживания вашей схемы.

  • settings.DEFAULT_SCHEMA_CLASS позволяет вам указать подкласс AutoSchema, который будет использоваться по умолчанию в вашем проекте.

В следующих разделах рассказывается подробнее.

Генерация схемы OpenAPI

Установите зависимости

pip install pyyaml uritemplate inflection
  • pyyaml используется для генерации схемы в формат OpenAPI на основе YAML.

  • uritemplate используется для получения параметров в пути.

  • inflection для более подходящего множественного числа операций в конечных точках списка.

Генерация статической схемы с помощью команды управления 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: Может использоваться для предоставления описательного заголовка для определения схемы.

  • description: Более длинный описательный текст.

  • version: Версия API.

  • url: Может использоваться для передачи канонического базового URL для схемы.

    schema_view = get_schema_view(
        title='API мониторинга серверов',
        url='https://www.example.org/api/'
    )
  • urlconf: Строка, представляющая путь импорта к URL conf, для которого вы хотите сгенерировать схему API. По умолчанию это значение соответствует значению параметра Django ROOT_URLCONF.

    schema_view = get_schema_view(
        title='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='API мониторинга серверов',
        url='https://www.example.org/api/',
        patterns=schema_url_patterns,
    )
  • public: Может использоваться для указания того, должна ли схема обходить разрешения представления. По умолчанию False

  • 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.

  • description: Более длинный описательный текст.

  • 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=None, public=False)

Возвращает словарь, представляющий схему OpenAPI:

generator = SchemaGenerator(title='Stock Prices API')
schema = generator.get_schema()

Аргумент request является необязательным и может быть использован, если вы хотите применить разрешения для каждого пользователя к результирующей генерации схемы.

Например, вы можете добавить условия обслуживания в объект верхнего уровня info:

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. В терминах DRF это отображения сериализаторов, которые описывают тела запроса и ответа.

  • Соответствующий объект операции OpenAPI, описывающий конечную точку, включая путь и параметры запроса для пагинации, фильтрации и так далее.

components = auto_schema.get_components(...)
operation = auto_schema.get_operation(...)

При компиляции схемы SchemaGenerator вызывает get_components() и get_operation() для каждого представления, разрешенного метода и пути.


Примечание: Автоматическая интроспекция компонентов и многих параметров операций опирается на соответствующие атрибуты и методы GenericAPIView: get_serializer(), pagination_class, filter_backends и т.д. По этой причине для базовых подклассов APIView интроспекция по умолчанию ограничивается именованными параметрами пути URL.


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__() именованный аргумент для вашего базового подкласса 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__(), но для наиболее часто используемых опций они есть.

Методы AutoSchema

get_components().

Генерирует компоненты OpenAPI, описывающие тела запросов и ответов, получая их свойства от сериализатора.

Возвращает словарь, отображающий имя компонента на сгенерированное представление. По умолчанию он содержит только одну пару, но вы можете переопределить get_components(), чтобы вернуть несколько пар, если ваше представление использует несколько сериализаторов.

get_component_name().

Вычисляет имя компонента из сериализатора.

Вы можете увидеть предупреждения, если в вашем API есть дублирующиеся имена компонентов. В этом случае вы можете переопределить get_component_name() или передать component_name __init__() именованный аргумент (см. ниже), чтобы обеспечить разные имена.

get_reference().

Возвращает ссылку на компонент сериализатора. Это может быть полезно, если вы переопределите get_schema().

map_serializer().

Сопоставляет сериализаторы с их представлениями OpenAPI.

Большинство сериализаторов должны соответствовать стандартному типу OpenAPI object, но вы можете переопределить map_serializer(), чтобы настроить это или другие поля на уровне сериализатора.

map_field().

Сопоставляет отдельные поля сериализатора с их схемным представлением. Базовая реализация будет работать с полями по умолчанию, которые предоставляет DRF.

Для экземпляров 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__(), чтобы вручную указать теги (см. ниже), или переопределить get_tags(), чтобы обеспечить пользовательскую логику.

get_operation().

Возвращает объект операции OpenAPI, описывающий конечную точку, включая путь и параметры запроса для пагинации, фильтрации и так далее.

Вместе с 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__()

AutoSchema предоставляет ряд именованных аргументов __init__(), которые могут быть использованы для общей настройки, если сгенерированные по умолчанию значения не подходят.

Доступные именованные аргументы следующие:

  • tags: Укажите список тегов.

  • component_name: Укажите имя компонента.

  • operation_id_base: Укажите часть имени ресурса в идентификаторах операций.

Вы передаете именованные аргументы при объявлении экземпляра AutoSchema в вашем представлении:

class PetDetailView(generics.RetrieveUpdateDestroyAPIView):
    schema = AutoSchema(
        tags=['Pets'],
        component_name='Pet',
        operation_id_base='Pet',
    )
    ...

Предполагая модель Pet и сериализатор PetSerializer, именованные аргументы в этом примере, вероятно, не нужны. Однако, часто вам придется передавать именованные аргументы, если у вас есть несколько представлений, нацеленных на одну и ту же модель, или несколько представлений с одинаковыми именами сериализаторов.

Если ваши представления имеют связанные настройки, которые часто требуются, вы можете создать базовый подкласс AutoSchema для вашего проекта, который принимает дополнительные __init__() именованные аргументы, чтобы избежать подклассификации AutoSchema для каждого представления.

Last updated