官方原文链接
本系列文章 github 地址
转载请注明出处
Schemas
API schema 是一个非常有用的工具,它允许一系列用例,包括生成参考文档,或者驱动可以与 API 交互的动态客户端库。
安装 Core API
你需要安装 coreapi
软件包才能为 REST framework 添加 schema 支持。
pip install coreapi
复制代码
内部 schema 表示
REST framework 使用 Core API 以便以独立于格式的表示对 schema 信息建模。这些信息可以被渲染成各种不同的 schema 格式,或者用于生成 API 文档。
在使用 Core API 时,schema 表示为 Document
,它是有关 API 信息的顶级容器对象。可用的 API 交互使用 Link
对象表示。每个链接都包含一个 URL,HTTP 方法,并且可能包含一个 Field
实例列表,它描述了 API 端点可以接受的任何参数。Link
和 Field
实例还可能包含描述,允许将 API schema 渲染到用户文档中。
以下是包含单个搜索端点的 API 说明示例:
coreapi.Document(
title='Flight Search API',
url='https://api.example.org/',
content={
'search': coreapi.Link(
url='/search/',
action='get',
fields=[
coreapi.Field(
name='from',
required=True,
location='query',
description='City name or airport code.'
),
coreapi.Field(
name='to',
required=True,
location='query',
description='City name or airport code.'
),
coreapi.Field(
name='date',
required=True,
location='query',
description='Flight date in "YYYY-MM-DD" format.'
)
],
description='Return flight availability and prices.'
)
}
)
复制代码
Schema 输出格式
为了呈现在 HTTP 响应中,必须将内部表示渲染为响应中使用的实际字节。
Core JSON 被设计为与 Core API 一起使用的规范格式。REST framework 包含用于处理此媒体类型的渲染器类,该渲染器类可用作 renderers.CoreJSONRenderer
。
备用 schema 格式
其他 schema 格式(如 Open API(“Swagger”),JSON HyperSchema 或 API Blueprint)也可以通过实现处理将 Document
实例转换为字符串表示形式的自定义渲染器类来支持。
如果有一个 Core API 编解码器包支持将编码格式化为你要使用的格式,则可以使用编解码器来实现渲染器类。
举个栗子
例如,openapi_codec
包提供对 Open API(“Swagger”)格式的编码或解码支持:
from rest_framework import renderers
from openapi_codec import OpenAPICodec
class SwaggerRenderer(renderers.BaseRenderer):
media_type = 'application/openapi+json'
format = 'swagger'
def render(self, data, media_type=None, renderer_context=None):
codec = OpenAPICodec()
return codec.dump(data)
复制代码
Schemas vs 超媒体
值得指出的是,Core API 也可以用来模拟超媒体响应,它为 API schema 提供了另一种交互风格。
通过 API schema,整个可用接口作为单个端点呈现在前端。然后,对各个 API 端点的响应通常会以普通数据的形式呈现,而不会在每个响应中包含任何进一步的交互。
使用超媒体,客户端会看到包含数据和可用交互的文档。每次交互都会生成一个新文档,详细说明当前状态和可用交互。
创建一个 schema
REST framework 包含用于自动生成 schema 的功能,或者允许你明确指定。
手动 Schema 规范
要手动指定 schema,请创建一个 Core API Document
,与上例类似。
schema = coreapi.Document(
title='Flight Search API',
content={
...
}
)
复制代码
自动 Schema 生成
自动 schema 生成由 SchemaGenerator
类提供。
SchemaGenerator
处理路由 URL pattterns 列表并编译适当结构化的 Core API 文档。
基本用法只是为 schema 提供标题并调用 get_schema()
:
generator = schemas.SchemaGenerator(title='Flight Search API')
schema = generator.get_schema()
复制代码
按视图 schema 自定义
默认情况下,查看自省是由可通过 APIView
上的 schema
属性访问的 AutoSchema
实例执行的。这为视图,请求方法和路径提供了适当的 Core API Link
对象:
auto_schema = view.schema
coreapi_link = auto_schema.get_link(...)
复制代码
(在编译模式时,SchemaGenerator
为每个视图,允许的方法和路径调用 view.schema.get_link()
。)
注意: 对于基本的 APIView
子类,默认内省本质上仅限于 URL kwarg 路径参数。对于包含所有基于类的视图的 GenericAPIView
子类,AutoSchema
将尝试自省列化器,分页和过滤器字段,并提供更丰富的路径字段描述。(这里的关键钩子是相关的 GenericAPIView
属性和方法:get_serializer
,pagination_class
,filter_backends
等。)
要自定义 Link
生成,你可以:
1)使用 manual_fields
kwarg 在你的视图上实例化 AutoSchema
:
from rest_framework.views import APIView
from rest_framework.schemas import AutoSchema
class CustomView(APIView):
...
schema = AutoSchema(
manual_fields=[
coreapi.Field("extra_field", ...),
]
)
复制代码
这允许扩展最常见的情况而不需要子类化。
2)提供具有更复杂定制的 AutoSchema
子类:
from rest_framework.views import APIView
from rest_framework.schemas import AutoSchema
class CustomSchema(AutoSchema):
def get_link(...):
# Implement custom introspection here (or in other sub-methods)
class CustomView(APIView):
...
schema = CustomSchema()
复制代码
这提供了对查看内省的完全控制。
3)在你的视图上实例化 ManualSchema
,显式为视图提供 Core API Fields
:
from rest_framework.views import APIView
from rest_framework.schemas import ManualSchema
class CustomView(APIView):
...
schema = ManualSchema(fields=[
coreapi.Field(
"first_field",
required=True,
location="path",
schema=coreschema.String()
),
coreapi.Field(
"second_field",
required=True,
location="path",
schema=coreschema.String()
),
])
复制代码
这允许手动指定某些视图的 schema,同时在别处保持自动生成。
通过将 schema
设置为 None
,你可以禁用视图的 schema 生成:
class CustomView(APIView):
...
schema = None # Will not appear in schema
复制代码
添加 schema 视图
有几种不同的方式可以将 schema 视图添加到你的 API 中,具体取决于你需要的内容。
get_schema_view 快捷方式
在你的项目中包含 schema 的最简单方法是使用 get_schema_view()
函数。
from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(title="Server Monitoring API")
urlpatterns = [
url('^$', schema_view),
...
]
复制代码
添加视图后,你将能够通过 API 请求来检索自动生成的 schema 定义。
$ http http://127.0.0.1:8000/ Accept:application/coreapi+json
HTTP/1.0 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/vnd.coreapi+json
{
"_meta": {
"title": "Server Monitoring API"
},
"_type": "document",
...
}
复制代码
get_schema_view()
的参数是:
title
可用于为 schema 定义提供描述性标题。
url
可用于为 schema 传递规范 URL。
schema_view = get_schema_view(
title='Server Monitoring API',
url='https://www.example.org/api/'
)
复制代码
urlconf
表示要为其生成 API schema 的 URL conf 的导入路径的字符串。这默认为 Django 的 ROOT_URLCONF setting 的值。
schema_view = get_schema_view(
title='Server Monitoring API',
url='https://www.example.org/api/',
urlconf='myproject.urls'
)
复制代码
renderer_classes
可用于传递渲染 API 根端点的渲染器类列表。
from rest_framework.schemas import get_schema_view
from rest_framework.renderers import CoreJSONRenderer
from my_custom_package import APIBlueprintRenderer
schema_view = get_schema_view(
title='Server Monitoring API',
url='https://www.example.org/api/',
renderer_classes=[CoreJSONRenderer, APIBlueprintRenderer]
)
复制代码
patterns
将 schema 内省限定为 url patterns 列表。如果你只想将 myproject.api
url 公开在 schema 中:
schema_url_patterns = [
url(r'^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
可用于指定要传递给 SchemaView
的 SchemaGenerator
子类。
authentication_classes
可用于指定将应用于 schema 端点的认证类列表。默认为 settings.DEFAULT_AUTHENTICATION_CLASSES
permission_classes
可用于指定将应用于 schema 端点的权限类列表。默认为 settings.DEFAULT_PERMISSION_CLASSES
使用显式 schema 视图
如果你需要比 get_schema_view()
快捷方式更多的控制权,那么你可以直接使用 SchemaGenerator
类来自动生成 Document
实例,并从视图中返回该实例。
此选项使你可以灵活地设置 schema 端点,并使用你想要的任何行为。例如,你可以将不同的权限,限流或身份验证策略应用于 schema 端点。
以下是使用 SchemaGenerator
和视图一起返回 schema 的示例。
views.py:
from rest_framework.decorators import api_view, renderer_classes
from rest_framework import renderers, response, schemas
generator = schemas.SchemaGenerator(title='Bookings API')
@api_view()
@renderer_classes([renderers.CoreJSONRenderer])
def schema_view(request):
schema = generator.get_schema(request)
return response.Response(schema)
复制代码
urls.py:
urlpatterns = [
url('/', schema_view),
...
]
复制代码
你也可以为不同的用户提供不同的 schema,具体取决于他们拥有的权限。这种方法可以用来确保未经身份验证的请求以不同的模式呈现给已验证的请求,或者确保 API 的不同部分根据角色对不同用户可见。
为了呈现一个 schema,其中包含由用户权限过滤的端点,你需要将 request
参数传递给 get_schema()
方法,如下所示:
@api_view()
@renderer_classes([renderers.CoreJSONRenderer])
def schema_view(request):
generator = schemas.SchemaGenerator(title='Bookings API')
return response.Response(generator.get_schema(request=request))
复制代码
显式 schema 定义
自动生成方法的替代方法是通过在代码库中声明 Document
对象来明确指定 API schema 。这样做会多一点工作,但确保你完全控制 schema 表示。
import coreapi
from rest_framework.decorators import api_view, renderer_classes
from rest_framework import renderers, response
schema = coreapi.Document(
title='Bookings API',
content={
...
}
)
@api_view()
@renderer_classes([renderers.CoreJSONRenderer])
def schema_view(request):
return response.Response(schema)
复制代码
静态 schema 文件
最后的选择是使用 Core JSON 或 Open API 等可用格式之一将你的 API schema 编写为静态文件。
然后你可以:
- 将模式定义写为静态文件,并直接提供静态文件。
- 编写一个使用
Core API
加载的 schema 定义,然后根据客户端请求将其渲染为多种可用格式之一。
作为文档的 Schemas
API schemas 的一个常见用法是使用它们来构建文档页面。
REST framework 中的 schema 生成使用文档字符串来自动填充 schema 文档中的描述。
这些描述将基于:
- 对应方法的文档字符串(如果存在)。
- 类文档字符串中的命名部分,可以是单行或多行。
- 类文档字符串。
举个栗子
一个 APIView
,带有明确的方法文档字符串。
class ListUsernames(APIView):
def get(self, request):
"""
Return a list of all user names in the system.
"""
usernames = [user.username for user in User.objects.all()]
return Response(usernames)
复制代码
一个 ViewSet
,带有一个明确的 action 文档字符串。
class ListUsernames(ViewSet):
def list(self, request):
"""
Return a list of all user names in the system.
"""
usernames = [user.username for user in User.objects.all()]
return Response(usernames)
复制代码
类文档字符串中带有 action 的通用视图,使用单行样式。
class UserList(generics.ListCreateAPIView):
"""
get: List all the users.
post: Create a new user.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAdminUser,)
复制代码
使用多行样式的类文档字符串中带有 action 的通用视图集。
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
retrieve:
Return a user instance.
list:
Return all users, ordered by most recently joined.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
复制代码
API 参考
SchemaGenerator
一个遍历路由 URL patterns 列表的类,为每个视图请求 schema 并整理生成的 CoreAPI 文档。
通常你会用一个参数实例化 SchemaGenerator
,如下所示:
generator = SchemaGenerator(title='Stock Prices API')
复制代码
参数:
title
必需 - API 的名称。url
- API schema 的 root URL。除非 schema 包含在路径前缀下,否则此选项不是必需的。patterns
- 生成 schema 时要检查的 URL 列表。默认为项目的 URL conf。urlconf
- 生成 schema 时使用的 URL conf 模块名称。 默认为settings.ROOT_URLCONF
.
get_schema(self, request)
返回表示 API schema 的 coreapi.Document
实例。
@api_view
@renderer_classes([renderers.CoreJSONRenderer])
def schema_view(request):
generator = schemas.SchemaGenerator(title='Bookings API')
return Response(generator.get_schema())
复制代码
request
参数是可选的,如果你希望将每个用户的权限应用于生成的 schema ,则可以使用该参数。
get_links(self, request)
返回一个嵌套的字典,其中包含在 API schema 中的所有链接。
如果要修改生成的 schema 的结构,重写该方法很合适,因为你可以使用不同的布局构建新的字典。
AutoSchema
一个处理 schema 生成的个别视图内省的类。
AutoSchema
通过 schema
属性附加到 APIView
。
AutoSchema
构造函数接受一个关键字参数 manual_fields
。
manual_fields
: 将添加到生成的字段的 coreapi.Field
实例 list
。具有匹配名称的生成字段将被覆盖。
class CustomView(APIView):
schema = AutoSchema(manual_fields=[
coreapi.Field(
"my_extra_field",
required=True,
location="path",
schema=coreschema.String()
),
])
复制代码
对于通过继承 AutoSchema
来自定义 schema 生成。
class CustomViewSchema(AutoSchema):
"""
Overrides `get_link()` to provide Custom Behavior X
"""
def get_link(self, path, method, base_url):
link = super().get_link(path, method, base_url)
# Do something to customize link here...
return link
class MyView(APIView):
schema = CustomViewSchema()
复制代码
以下方法可覆盖。
get_link(self, path, method, base_url)
返回与给定视图相对应的 coreapi.Link
实例。
这是主要的入口点。如果你需要为特定视图提供自定义行为,则可以覆盖此内容。
get_description(self, path, method)
返回用作链接描述的字符串。默认情况下,这基于上面的 “作为文档的 Schemas” action 中描述的视图文档字符串。
get_encoding(self, path, method)
与给定视图交互时返回一个字符串,以指定任何请求主体的编码。 例如 'application/json'
。可能会返回一个空白字符串,以便查看不需要请求主体的视图。
get_path_fields(self, path, method):
返回 coreapi.Link()
实例列表。用于 URL 中的每个路径参数。
get_serializer_fields(self, path, method)
返回 coreapi.Link()
实例列表。用于视图使用的序列化类中的每个字段。
get_pagination_fields(self, path, method)
返回 coreapi.Link()
实例列表,该列表由 get_schema_fields()
方法返回给视图使用的分页类。
get_filter_fields(self, path, method)
返回 coreapi.Link()
实例列表,该列表是由视图所使用的过滤器类的 get_schema_fields()
方法返回的。
get_manual_fields(self, path, method)
返回 coreapi.Field()
实例列表以添加或替换生成的字段。默认为(可选)传递给 AutoSchema
构造函数的 manual_fields
。
可以通过 path
或 method
覆盖自定义 manual field。例如,每个方法的调整可能如下所示:
def get_manual_fields(self, path, method):
"""Example adding per-method fields."""
extra_fields = []
if method=='GET':
extra_fields = # ... list of extra fields for GET ...
if method=='POST':
extra_fields = # ... list of extra fields for POST ...
manual_fields = super().get_manual_fields(path, method)
return manual_fields + extra_fields
复制代码
update_fields(fields, update_with)
实用的 staticmethod
。封装逻辑以通过 Field.name
添加或替换列表中的字段。可能会被覆盖以调整替换标准。
ManualSchema
允许手动为 schema 提供 coreapi.Field
实例的列表,以及一个可选的描述。
class MyView(APIView):
schema = ManualSchema(fields=[
coreapi.Field(
"first_field",
required=True,
location="path",
schema=coreschema.String()
),
coreapi.Field(
"second_field",
required=True,
location="path",
schema=coreschema.String()
),
]
)
复制代码
ManualSchema
构造函数有两个参数:
fields
: coreapi.Field
实例列表。必需。
description
: 字符串描述。可选的。
Core API
本文档简要介绍了用于表示 API schema 的 coreapi
包内的组件。
请注意,这些类是从 coreapi
包导入的,而不是从 rest_framework
包导入的。
Document
表示 API schema 的容器。
title
API 的名称。
url
API 的规范 URL。
content
一个字典,包含 schema 的 Link
对象。
为了向 schema 提供更多结构,content
字典可以嵌套,通常是二层。例如:
content={
"bookings": {
"list": Link(...),
"create": Link(...),
...
},
"venues": {
"list": Link(...),
...
},
...
}
复制代码
Link
代表一个单独的 API 端点。
url
端点的 URL。可能是一个 URI 模板,例如 /users/{username}/
。
action
与端点关联的 HTTP 方法。请注意,支持多个 HTTP 方法的 url 应该对应于每个 HTTP 方法的单个链接。
fields
Field
实例列表,描述输入上的可用参数。
description
对端点的含义和用途的简短描述。
Field
表示给定 API 端点上的单个输入参数。
name
输入的描述性名称。
required
boolean 值,表示客户端是否需要包含值,或者参数是否可以省略。
location
确定如何将信息编码到请求中。应该是以下字符串之一:
"path"
包含在模板化的 URI 中。例如,/products/{product_code}/
的 url
值可以与 "path"
字段一起使用,以处理 URL 路径中的 API 输入,例如 /products/slim-fit-jeans/
。
这些字段通常与项目 URL conf 中的命名参数对应。
"query"
包含为 URL 查询参数。例如 ?search=sale
。通常用于 GET
请求。
这些字段通常与视图上的分页和过滤控件相对应。
"form"
包含在请求正文中,作为 JSON 对象或 HTML 表单的单个 item。例如 {"colour": "blue", ...}
。通常用于POST
,PUT
和 PATCH
请求。多个 "form"
字段可能包含在单个链接上。
这些字段通常与视图上的序列化类字段相对应。
"body"
包含完整的请求主体。通常用于 POST
, PUT
和 PATCH
请求。链接上不得存在超过一个 "body"
字段。不能与 "form"
字段一起使用。
这些字段通常对应于使用 ListSerializer
来验证请求输入或使用文件上载的视图。
encoding
"application/json"
JSON编码的请求内容。对应于使用 JSONParser
的视图。仅在 Link
中包含一个或多个 location="form"
字段或单个 location="body"
字段时有效。
"multipart/form-data"
Multipart 编码的请求内容。对应于使用 MultiPartParser
的视图。仅在 Link
中包含一个或多个 location="form"
字段时有效。
"application/x-www-form-urlencoded"
URL encode 的请求内容。对应于使用 FormParser
的视图。仅在 Link
中包含一个或多个 location="form"
字段时有效。
"application/octet-stream"
二进制上传请求内容。对应于使用 FileUploadParser
的视图。仅在 Link
中包含 location="body"
字段时有效。
description
对输入字段的含义和用途的简短描述。