Django REST framework API 指南(21):Schemas

官方原文連接
本系列文章 github 地址
轉載請註明出處前端

Schemas

API schema 是一個很是有用的工具,它容許一系列用例,包括生成參考文檔,或者驅動能夠與 API 交互的動態客戶端庫。python

安裝 Core API

你須要安裝 coreapi 軟件包才能爲 REST framework 添加 schema 支持。git

pip install coreapi
複製代碼

內部 schema 表示

REST framework 使用 Core API 以便以獨立於格式的表示對 schema 信息建模。這些信息能夠被渲染成各類不一樣的 schema 格式,或者用於生成 API 文檔。github

在使用 Core API 時,schema 表示爲 Document,它是有關 API 信息的頂級容器對象。可用的 API 交互使用 Link 對象表示。每一個連接都包含一個 URL,HTTP 方法,而且可能包含一個 Field 實例列表,它描述了 API 端點能夠接受的任何參數。LinkField 實例還可能包含描述,容許將 API schema 渲染到用戶文檔中。django

如下是包含單個搜索端點的 API 說明示例:json

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 響應中,必須將內部表示渲染爲響應中使用的實際字節。api

Core JSON 被設計爲與 Core API 一塊兒使用的規範格式。REST framework 包含用於處理此媒體類型的渲染器類,該渲染器類可用做 renderers.CoreJSONRendererbash

備用 schema 格式

其餘 schema 格式(如 Open API(「Swagger」),JSON HyperSchema 或 API Blueprint)也能夠經過實現處理將 Document 實例轉換爲字符串表示形式的自定義渲染器類來支持。app

若是有一個 Core API 編解碼器包支持將編碼格式化爲你要使用的格式,則可使用編解碼器來實現渲染器類。ide

舉個栗子

例如,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_serializerpagination_classfilter_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

可用於指定要傳遞給 SchemaViewSchemaGenerator 子類。

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

能夠經過 pathmethod 覆蓋自定義 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", ...}。一般用於POSTPUTPATCH 請求。多個 "form" 字段可能包含在單個連接上。

這些字段一般與視圖上的序列化類字段相對應。

"body"

包含完整的請求主體。一般用於 POST, PUTPATCH 請求。連接上不得存在超過一個 "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

對輸入字段的含義和用途的簡短描述。

相關文章
相關標籤/搜索