DPF-Auto - это мощный и гибкий инструмент для легкого создания мощных Web APIs.
DPF-Auto - это мощный и гибкий инструмент для легкого создания мощных Web APIs. Мы умеем:
- Автоматическое формирование документации вашего API для фронт разработчиков. Документация формируется не в html документах, а во view, который можно повесить на ссылку и настроить многие вещи. Идея была позаимствована и развита у drfdocs.com, за что ему большая благодарность.
- Автоматическое тестирование вашего API. Полное тестирование всей схемы API, на предмет соответствия документации, принимаемых возвращаемых данных, соответствия поведению с ошибками, соответствия схеме JSON.
- Помощь в написании view для API. Помощь в обработке ошибок, простая и гибкая система работы с входящими данными и исходящими данными. Помогает с легкостью держать единую схему JSON как на всем проекте, так и на отдельных блоках проекта. Позволяет создать свою единую базу ошибок, и кодов ошибок, возвращаемых клиенту.
- Разные полезные утилиты, которые были позаимствованы из разных протоколов, разных утилит, и разных реализаций. Пример:
GraphQLField
.
Этот пакет не является полноценно самостоятельным для построения REST API. Это доработка вокруг django-rest-framework.org позволяющая писать ваше API еще проще и еще мощнее.
- Python (3.4, 3.5, 3.6)
- Django (1.9, 1.10, 1.11)
- DjangoRestFramework (3)
Установка через pip
...
pip install git+https://github.com/nxexox/django-rest-framework-auto.git
Добавить 'drf_auto'
в ваши INSTALLED_APPS
в настройках.
INSTALLED_APPS = (
...
'drf_auto',
)
Давайте рассмотрим примеры использования по порядку.
- Документация.
- Написание View.
- Тестирование.
- Комбинирование для упрощения кода.
- Настройки.
- Обработка ошибок.
Для начала напишите свое первое view и зарегистрируем его в роутере.
class TestView(APIView):
"""
Тестовый поинт, для проверки работы автодокументации.
"""
http_method_names = ['get', 'post', 'put', 'delete']
docs_serializer_classes = {
'get': GetExampleSerializer,
'post': {
'in': PostInExampleSerializer,
'out': PostOutExampleSerializer
}
}
docs_exclude_fields = {
'post': ['exclude_field', 'exclude_field_two']
}
GetExampleSerializer, PostInExampleSerializer, PostOutExampleSerializer
- любые стандартные rest_framework.serializers.Serializer, rest_framework.serializers.ModelSerializer
, используются для примера.
Затем нужно подключить view с документацией в роутер.
from django.conf.urls import url, include
from test_app.views import TestView
from drf_auto.views import DRFDocsView
urlpatterns = [
url(r'^test-view/$', TestView.as_view()),
url(r'^api-docs/$', DRFDocsView.as_view(), name='docs')
]
## OR ##
from drf_auto import urls as api_docs_urls
urlpatterns = [
url(r'^test-view/$', TestView.as_view()),
url(r'^api-docs/', include(api_docs_urls))
]
После этого можно открывать страницу api-docs
и там будет динамически сгенерирована документация. Обратите внимание, в первом случае мы указывали name='docs'
, а во втором нет. Во втором случае name='docs'
уже указано внутри api_docs_urls
. Не беспокойтесь, параметрами name, namespace
можно управлять через настройки.
Если вы добавите еще несколько разных view, то автодока их все подтянет и отобразит. Главное что бы они были зарегистрированы в urls
проекта.
Для управления отображения в автодокументации поинтов и описания, нужно разобраться как работает автодока.
- В базовое описание поинта попадает
__doc__
view
объекта, т.е. класса. - В описание каждого метода попадает
__doc__
каждого метода. Если мы реализуем методget
уTestView
тогда в описании методаget
будет эта документация. Тут лучше всего описыватьurl
параметры вида(?P<pk>\d+)
. - Блоки
Принимает
/Возвращает
формируются благодаря дополнительному полюdocs_serializer_classes
. Где ключом является метод, а значением является описание метода через сериалайзеры. Есть несколько вариантов использования словаря: -
- Указать метод и один сериалайзер:
'get': GetExampleSerializer
. В таком случае в блокВозвращает
попадет описание этого сериалайзера. Автодокументация возьмет все филды и опишет их. Тип филда, подпись (label
илиverbose_name
) в зависимости от типа филда. В блокПринимает
не попадет ничего, и он просто не отобразиться в документации.
- Указать метод и один сериалайзер:
-
- Указать метод и точное описание метода.
В таком случае в блок'post': { 'in': PostInExampleSerializer, 'out': PostOutExampleSerializer }
Принимает
попадет описаниеPostInExampleSerializer
сериалайзера. А в блокВозвращает
попадет описаниеPostOutExampleSerializer
сериалайзера. Так же, можно указать только один из двух ключейin
/out
. В таком случае только один ключ попадет в документацию, а второй будет игнорирован и исключен из документации. -
- Не описывать метод вовсе. В таком случае блоки
Принимает
/Возвращает
будут исключены, и вместо них будет блокALL
. Содержимое его будет описанием сериалайзера из атрибутаserializer_class
. Если таковой установлен. Т.е. автодока сама попытается найти сериалайзер для отображения документации.
- Не описывать метод вовсе. В таком случае блоки
- Дополнительно можно во view установить атрибут
docs_exclude_fields
. Это словарь, где ключ метод, значение список филдов. Эти филды для этого метода будут исключены из документации. Например вы хотите давать пользователю создавать статью, но привязку пользователя к статье брать изrequest.user
, в таком случае просто искчлючите из документации филд пользователя, а самостоятельно пробрасывайте его в данные перед созданием. - Есть еще одна полезная вещь для описания документации сериалайзеров. Если у вас в сериалайзере используется
serializers.SerializerMethodField
, вы можете описать автоматически и его. Для этого в сериалайзере с таким методом, нужно прописатьclass Meta
, внутри него описать атрибутdoc_method_fields_classes
который является словарем. Где ключ это название филда, а значение, это готовый сериалайзер, из которого можно сформировать документацию. В таком случае этот метод будет описан этим сериалайзером. Пример:from rest_framework import serializers class DocsSerializer(serializers.Serializer): test = serializers.CharField(label='Какое то описание') class TestSerializer(serializers.Serializer): test_field = serializers.SerializerMethodField() class Meta: doc_method_fields_classes = { 'test_field': DocsSerializer } def get_test_field(self, obj): return {'test': 'result'}
Для полноценного использования всех возможностей DRF-Auto
, писать view
нужно через классы, и наследоваться от DRF-Auto views
.
Есть несколько базовых классов. Все находятся в drf_auto.views.rest
:
AutoPointFailRequest(rest_framework.generics.GenericAPIView)
- Класс для удобной работы с ошибками во время обработки запроса.AutoSearchSerializerView(AutoPointFailRequest)
- Класс для поиска сериалайзера для обработки данных. Используется в обработке запроса и ответа.AutoResponseSerializerView(AutoSearchSerializerView)
- Класс для автоматического формирования ответа от поинта.AutoRequestSerializerView(AutoPointFailRequest)
- Класс для помощи в обработке запроса.RestAPIView(AutoRequestSerializerView, AutoResponseSerializerView)
- Базовый класс для всех рест апи, которые вы будете использовать.RestListAPIView(AutoRequestSerializerView, rest_framework.generics.ListAPIView, AutoResponseSerializerView)
- Genericview
class для списка.RestRetrieveAPIView(AutoRequestSerializerView, rest_framework.generics.RetrieveAPIView, AutoResponseSerializerView)
- Genericview
class, для конкретного объекта.RestUpdateAPIView(AutoRequestSerializerView, rest_framework.generics.UpdateAPIView, AutoResponseSerializerView)
- Genericview
class для изменения объекта.RestCreateAPIView(AutoRequestSerializerView, rest_framework.generics.CreateAPIView, AutoResponseSerializerView)
- Genericview
class для создания объекта.RestDestroyAPIView(AutoRequestSerializerView, rest_framework.generics.DestroyAPIView, AutoResponseSerializerView)
- Genericview
class для удаления объекта.
Класс предоставляет метод fail(status, code=None, message=None, data=None, fields=None)
который формирует и возвращает объект Response с ошибкой обработки запроса. Про обработку ошибок читайте тут
. Так же класс автоматически ловит и обрабатывает исключения в любом месте обработки запроса. Исключения ловит только drf_auto.exceptions.FailPointRequest, rest_framework.serializers.ValidationError
. Если он увидел такое исключение, тогда он формирует и возвращает соответствующий объект ответа.
status
- Код ответа сервера.code
- Код ответа в JSON. на верхнем уровне в объектеcode
. Если не указан, принимает значение status.message
- Сообщение которое следует вернуть. Если не указано, тогда пытается найти его в общем словаре описания ошибок, по ключуcode
. Про общий словарь читайте внастройках
.data
- Дополнительные данные которые необходимо вернуть, в любом JSON серилизуемом формате. Если не указано, то ключdata
в ответе отсутствует.fields
- Словарь филдов, для управления ответом. Ключ это ключ который вернется, значение, это ключ из стандартного набора атрибутов. Пример:{'response_code': 'code', 'response_message': 'message'}
. В таком случае ответ всегда будет фиксирован и выглядеть так:{'response_code': code, 'response_message': message}
.
В стандартном случае ответ ошибки выглядит так:
{
"code": "code",
"message": "message",
"data": "data"
}
Этот класс помогает искать сериалайзер для обработки ответа или запроса. Предоставляет метод get_serializer_class(is_response=False)
, с помощью которого и происходит поиск.
is_response
- Флаг, указывающий это поиск сериалайзера для формирования ответа, или обработки запроса?
Так же имеет ряд атрибутов настроект. По дефолту они настроены данными из настроек приложения, но для каждого поинта можно их менять.
serializers_response_field
- Название филда, для поиска словаря сериалайзеров для ответа. Дефолтное:serializer_classes
.serializers_request_field
- Название филда, для поиска словаря сериалайзеров для обработки запроса. Дефолтное:serializer_classes
.serializers_request_key
- Ключ используются для поиска внутри сериалайзеров. request_key - обработка водящих данных. Дефолтное:in
.serializers_response_key
- Ключ используются для поиска внутри сериалайзеров. response_key - обработка ответа сервера. Дефолтное:out
.
Этот класс предоставляет метод get_response(code, serializer=None, data=None, is_serializer=False, serializer_class=None, many=False, *args, **kwargs)
который формирует и возвращает объект ответа. Методу можно как отдавать готовые серилизованные данные так и необработанные данные и просить обработать сериалайзером. Он сам подберет сериалайзер в зависимости от настроек view
и сформирует ответ.
code
- Код ответа сервера.serializer
- Сериалайзер который уже хранит данные.data
- Данные, которые будут возвращены в ответе.is_serializer
- Флаг, указывающий нужно ли серилизовать данные или они уже готовы к ответу.serializer_class
- Класс сериалайзера которым нужно обработать данные. Если указан, тогда обработка будет этим сериалайзером.many
- Флаг указывающий, это один объект нужно обработать, или множество объектов нужно обработать сериалайзером.
Этот класс позволяет менять данные в запросе, до его обработки. Так же немного переопределяет логику поиска сериалайзера для обработки запроса.
get_initial_data(data)
метод позволяет менять данные в запросе.
data
- Данные, пришедшие в запросе.
Для работы с DRF-Auto
достаточно унаследоваться от RestAPIView
или любого Generic view
класса.
Настройки приложения прописаны в settings.py
вашего проекта.
Установите атрибут REST_FRAMEWORK_AUTO
в settings.py
. REST_FRAMEWORK_AUTO
- Это словарь.
Пример:
# ... your other settings
REST_FRAMEWORK_AUTO = {
'DOCS': {
'HIDE_DOCS': False,
'SERIALIZERS_ATTR_NAME': 'docs_serializer_classes',
'EXCLUDE_FIELDS_ATTR_NAME': 'docs_exclude_fields',
'SERIALIZER_DOC_ATTR': 'doc_method_fields_classes',
'PARSER_CLASS': 'drf_auto.autodocs.parsers.DefaultParser'
},
'AUTO_REST': {
'EXCEPTIONS': {
'PROCESS_EXCEPT': True,
'PROCESS_EXCEPT_HANDLER': None,
'CODE_EXCEPTION_LIST': 400,
'STATUS_EXCEPTION_LIST': 400,
'EXCEPTION_LIST': ['rest_framework.serializers.ValidationError'],
'EXCEPTION_DICT': {
'rest_framework.serializers.ValidationError': {
'status': 400,
'code': 400,
'message': 'Ошибка валидации. Неверные данные.',
'fields': {'status': 'status', 'code': 'code', 'message': 'message', 'data': 'data'},
'data_attr': 'detail',
},
},
},
},
'SERIALIZER_DOC_CODES': {'common': {}, 'specific': {}},
'SERIALIZERS_RESPONSE_FIELD': 'serializer_classes',
'SERIALIZERS_REQUEST_FIELD': 'serializer_classes',
'SERIALIZERS_REQUEST_KEY': 'in',
'SERIALIZERS_RESPONSE_KEY': 'out'
}
# ... your other settings
DOCS.HIDE_DOCS
- Скрыть ли документацию. Нужно например что бы скрывать документацию апи для разработчиков на продакшн стенде.DOCS.SERIALIZERS_ATTR_NAME
- Название атрибута, который будет уставновлен на всех view, для поиска словаря с описанием сериалайзеров для документации.DOCS.EXCLUDE_FIELDS_ATTR_NAME
- Название атрибута для исключения филдов из описания документации.DOCS.SERIALIZER_DOC_ATTR
- Название атрибута для описанияSerialiazerMethodField
у сериалайзеров. Прописывать вserializer.Meta
классе. Даже если класс неModelSerializer
.DOCS.PARSER_CLASS
- Путь до класса, который парсит сериалайзер и возвращает нужные данные для автодоки.AUTO_REST.EXCEPTIONS.PROCESS_EXCEPT
- Слудет ли обрабатывать исключения, возникшие при обработке запроса от клиента?AUTO_REST.EXCEPTIONS.PROCESS_EXCEPT_HANDLER
- Путь до своего обработчика исключений, во время обработки запроса. Принимаетexc
- экземпляр исключения. Возвращаетrest_framework.response.Response
- ответ от сервера. Работает только если включенPROCESS_EXCEPT
.AUTO_REST.EXCEPTIONS.EXCEPTION_LIST
- Список исключений, которые дополнительно стоит обработать помимоdrf_auto.exceptions.FailPointRequest
. Работает только если включенPROCESS_EXCEPT
.AUTO_REST.EXCEPTIONS.CODE_EXCEPTION_LIST
- Код ответа апи при ответе, во время обработки исключения.AUTO_REST.EXCEPTIONS.STATUS_EXCEPTION_LIST
- Код ответа сервера при ответе, во время обработки исключения.AUTO_REST.EXCEPTIONS.EXCEPTION_DICT
- Словарь с описанием как обрабатывать исключение. Ключ это само исключение из спискаEXCEPTION_LIST
. Значение это данные для методаfail
у апи. Все аргументы кромеdata
.data
берется из самого исключения. Для поиска данных в самом исключении используетсяdata_attr
. Это название атрибута у исключения, в котором хранятся данные по ошибке.SERIALIZER_DOC_CODES
- Единая база ошибок.SERIALIZERS_RESPONSE_FIELD
- Название филда, для поиска словаря сериалайзеров для ответа.SERIALIZERS_REQUEST_FIELD
- Название филда, для поиска словаря сериалайзеров для обработки запроса.SERIALIZERS_REQUEST_KEY
- Ключ используются для поиска внутри сериалайзеров. request_key - обработка водящих данных. Дефолтное:in
.SERIALIZERS_RESPONSE_KEY
- Ключ используются для поиска внутри сериалайзеров. response_key - обработка ответа сервера. Дефолтное:out
.
Сообщить клиенту про ошибку, можно двумя способами:
- Использовать метод
fail(status, code=None, message=None, data=None, fields=None, *args, **kwargs)
уview
класса. Он формирует и возвращаетResponse
, потому его результат нужно возвращать изview.
- Выбросить исключение
drf_auto.exceptions.FailPointRequest(status, code=None, message=None, data=None, fields=None, *args, **kwargs)
. Исключение имеет точно такую же сигнатуру что иfail
. По сути,fail
является оберткой надFailPointRequest
. В случае исключения, его можно бросать в любом месте запроса, тогда он будет пойман базовым классом и обработается как следует.
Сигнатура:
status
- Код ответа сервера.code
- Код ответа в JSON. на верхнем уровне в объектеcode
. Если не указан, принимает значение status.message
- Сообщение которое следует вернуть. Если не указано, тогда пытается найти его в общем словаре описания ошибок, по ключуcode
.data
- Дополнительные данные которые необходимо вернуть, в любом JSON серилизуемом формате. Если не указано, то ключdata
в ответе отсутствует.fields
- Словарь филдов, для управления ответом. Ключ это ключ который вернется, значение, это ключ из стандартного набора атрибутов. Пример:{'response_code': 'code', 'response_message': 'message'}
. В таком случае ответ всегда будет фиксирован и выглядеть так:{'response_code': code, 'response_message': message}
.
В стандартном случае ответ ошибки выглядит так:
{
"code": "code",
"message": "message",
"data": "data"
}
Общий словарь ошибок можно сформировать в настройках. Либо в другом месте и в настройках его пробросить. Пример:
{
"common": {
"1**": "Проблемы с правами на объект.",
"2**": "Не найдено.",
"3**": "Пока пусто",
"4**": "Неверный запрос."
},
"specific": {
"100": "У вас нет прав на просмотр объекта. Пожалуйста убедитесь в верности запрашиваемых данных.",
"101": "У вас нет прав на удаление объекта. Пожалуйста убедитесь в верности запроса.",
"102": "У вас нет прав на создание объекта. Пожалуйста убедитесь в верности запроса.",
"200": "Не найден родительский объект. Возможно он был удален или у вас не хватает прав.",
"400": "Плохой запрос. Неверные данные.",
"401": "Ошибка валидации."
}
}
Этот словарь отразиться в авто документации по апи. common
секция используется только для автодоки. Секция specific
используется как для автодоки, так и для поиска сообщения в ответе, когда произошла ошибка. Сообщение ищется по параметру code
у исключения drf_auto.exceptions.FailPointRequest
. Найденное сообщение попадет в message
ответа сервера.
По всем вопросам поддержки, создавайте issue или пишите разработчикам на почту. Проект в альфа версии, и потихоньку будет дорабатываться и улучшаться.