关于django:Django-Swagger文档库drfspectacular

在应用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)

对于以上问题咱们有两种解决形式:

  1. 只应用JSON格局的申请参数,毛病是必填和选填参数搞不清楚
  2. 在后端序列化的时候,针对不同的申请,明确的定义绝对应的序列化类来解决,毛病是后端代码变多了,而且湮没了DRF为咱们提供的很多使用方便的个性。

目前我采纳的是第一种形式,宁愿API不明确一点,也不能减少后端的复制水平。

关注“Python运维核心”,理解更多低代码开发

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理