Схема

Машиночитаемая [схема] описывает, какие ресурсы доступны через 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 для каждого представления.

Вернуться на верх