在应用 DRF 的时候,通常的文档有:默认文档 RestFrameWork、CoreAPI、Swagger,Swagger 是最风行的 API 文档库,在绝大多数服务端开发中都有用到,之前咱们应用了 CoreAPI 来生成文档,一方面是它不够风行,没方法和其余工具联合,另一方面可能是我不相熟,所有有些接口并不能依照咱们的要求来应用。因而我抉择应用 Swagger 文档,之前应用过 drf-yasg,然而 drf-yasg 当初还不反对 OpenAPI 3.0,而在 drf-yasg 的官网文档中为咱们举荐了另一个库:drf-spectacular,而且申明了 drf-yasg 不太可能反对 OpenAPI 3.0,因而举荐咱们应用 drf-spectacular 这个库。
装置配置
pipenv install drf-spectacular
在 app 中注册
# settings.py
INSTALLED_APPS = [
# ALL YOUR APPS
'drf_spectacular',
]
配置 DRF 默认 schema
# settings.py
REST_FRAMEWORK = {
# YOUR SETTINGS
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
配置 drf-spectacular
# settings.py
SPECTACULAR_SETTINGS = {
'TITLE': '在线考试',
'DESCRIPTION': '在线考试零碎',
'VERSION': '1.0.0',
'SERVE_INCLUDE_SCHEMA': False,
# OTHER SETTINGS
}
动态资源引入
drf-spectacular 默认不蕴含 UI 资源,采纳 CDN 形式引入网络内部资源,如果须要本地应用 UI 资源,能够依照一下形式引入:
pipenv install drf-spectacular[sidecar]
配置 settings.py 文件
INSTALLED_APPS = [
# ALL YOUR APPS
'drf_spectacular',
'drf_spectacular_sidecar', # required for Django collectstatic discovery
]
SPECTACULAR_SETTINGS = {
'SWAGGER_UI_DIST': 'SIDECAR', # shorthand to use the sidecar instead
'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
'REDOC_DIST': 'SIDECAR',
# OTHER SETTINGS
}
路由配置
在根 urls.py 中减少路由配置
from drf_spectacular.views import SpectacularJSONAPIView, SpectacularRedocView, SpectacularSwaggerView
urlpatterns = [path('swagger/json/', SpectacularJSONAPIView.as_view(), name='schema'),
# Optional UI:
path('swagger/ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
path('swagger/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
# YOUR PATTERNS
]
拜访:http://localhost:8000/swagger…
在 swagger 文档中为咱们生成的接口标签是依据根路由前缀主动生成的,例如以上文档的路由为:
urlpatterns = [path('', RedirectView.as_view(url='docs')),
path('swagger/json/', SpectacularJSONAPIView.as_view(), name='schema'),
# Optional UI:
path('swagger/ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
path('swagger/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
# My Router
path('user/', include('users.urls')),
path('exam/', include('exam.urls')),
path('question/', include('question.urls'))
]
如果想要批改指定接口所属的标签,咱们能够应用 drf-spectacular 提供的 extend_schema
装璜器函数,函数定义如下:
def extend_schema(operation_id: Optional[str] = None,
parameters: Optional[List[Union[OpenApiParameter, _SerializerType]]] = None,
request: Any = empty,
responses: Any = empty,
auth: Optional[List[str]] = None,
description: Optional[str] = None,
summary: Optional[str] = None,
deprecated: Optional[bool] = None,
tags: Optional[List[str]] = None,
exclude: bool = False,
operation: Optional[Dict] = None,
methods: Optional[List[str]] = None,
versions: Optional[List[str]] = None,
examples: Optional[List[OpenApiExample]] = None,
extensions: Optional[Dict[str, Any]] = None,
) -> Callable[[F], F]:
这个装璜器次要用于批改 view 在文档中的定义,参数意义如下:
- operation_id:一个惟一标识 ID,根本用不到
- parameters:增加到列表中的附加或替换参数去主动发现字段。
-
responses:替换
Serializer
。须要各种各样的可独自应用或组合应用的输出(有以下 7 种)Serializer
类- 序列化实例,比方:
Serializer(many=True)
OpenApiTypes
的根本类型或者实例OpenApiResponse
类PolymorphicProxySerializer
类- 1 个字典,以状态码作为键,以上其中一项作为值(是最罕用的,格局
{200, None}
) - 1 个字典,以状态码作为键,以
media_type
作为值
-
request:替换序列化,承受各种输出
Serializer
类或者实例OpenApiTypes
根本类型或者实例PolymorphicProxySerializer
类- 1 个字典,以
media_type
作为键,以上其中一项作为值
- auth:用 auth 办法的显式列表替换发现的 auth
- description:替换发现的文档字符串
- summary:一个可选的短的总结形容
- deprecated:将操作标记为已弃用
- tags:笼罩默认标记列表
- exclude:设置为 True 以从
schema
中排除操作 - operation:手动笼罩主动发现将生成的内容。你必须提供一个兼容
OpenAPI3
的字典,该字典能够间接翻译成YAML
。 - methods:查看
extend_schema
中非凡的办法,默认匹配所有 - versions:查看
extend_schema
中非凡的 API 版本,默认匹配所有 - example:将申请 / 响应示例附加到操作中
- extensions:标准扩大
最初咱们将登录、注册接口批改为 Common 标签
from drf_spectacular.utils import extend_schema
class LoginView(GenericAPIView):
......
@extend_schema(tags=['Common'],
summary='Login',
description='登录接口',
responses={200: str, 401: str}
)
def post(self, request: Request):
pass
class RegisterView(GenericAPIView):
......
@extend_schema(tags=['Common'],
summary='Register',
description='注册接口',
responses={201: UserInfoSerializer, 400: str}
)
def post(self, request: Request):
pass
留神:
应用时要留神,对于不同 app 下的 view 和 Serializer 要尽量应用不同的命名,否则在渲染文档的时候可能会出现异常。
自定义认证形式
在我的项目中咱们应用了 JWT 作为登录认证,而 drf-spectacular 只对 Session、Basic、Token 做了适配
rest_framework.authentication.SessionAuthentication
rest_framework.authentication.BasicAuthentication
rest_framework.authentication.TokenAuthentication
这个咱们在 drf-spectacular/authentication.py
文件中能够看到,这个的作用就是在文档中显示什么样认证页面
对于认证页面的显示,次要是依据 settings.py 配置中的
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'utils.auth.authentication.JwtAuthentication'
],
......
}
如果 drf-spectacular
能够辨认 DEFAULT_AUTHENTICATION_CLASSES
下的认证形式,就会在文档登录页面上显示对应的认证形式,这里咱们有自定义的认证形式,如果须要显示,要做一下适配:
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from drf_spectacular.plumbing import build_bearer_security_scheme_object
class JWTTokenScheme(OpenApiAuthenticationExtension):
target_class = 'utils.auth.authentication.JwtAuthentication'
name = 'JwtTokenAuth'
match_subclasses = True
priority = 1
def get_security_definition(self, auto_schema):
return build_bearer_security_scheme_object(
header_name='Authorization',
token_prefix=self.target.keyword,
bearer_format='JWT'
)
简略解释一下,首先要继承 OpenApiAuthenticationExtension
,而后target_class
中要写咱们在 DEFAULT_AUTHENTICATION_CLASSES
中配置的认证门路,而后从新 get_security_definition
函数,返回一个字典对象,字典的键能够在 OpenAPI Specification v3.0.3 | Introduction, Definitions, & More 网页拜访
而后再看登录认证页面
因为咱们在 DEFAULT_AUTHENTICATION_CLASSES
中配置了两种认证形式,因而页面就会显示两种认证形式
BUG
目前应用中存在一个 BUG,就是对于 read_only 字段,依照咱们的了解就是在查问申请是返回给客户端,而创立时在申请体中不须要蕴含。在默认生成的 swagger 界面上,咱们看到的状况与了解的一样,对于 JSON 参数的申请是没有问题的,咱们只须要输出必填的字段就能够了,然而如果是 form-data 参数,尽管显示的仍然不蕴含 read_only 字段,申请却无奈发送胜利。作者也认为这是一个 BUG,然而他却没有修改,
Callback schema with read-only/write-only fields · Issue #680 · tfranzel/drf-spectacular (github.com)
对于以上问题咱们有两种解决形式:
- 只应用 JSON 格局的申请参数,毛病是必填和选填参数搞不清楚
- 在后端序列化的时候,针对不同的申请,明确的定义绝对应的序列化类来解决,毛病是后端代码变多了,而且湮没了 DRF 为咱们提供的很多使用方便的个性。
目前我采纳的是第一种形式,宁愿 API 不明确一点,也不能减少后端的复制水平。
关注“Python 运维核心”,理解更多低代码开发