如何編寫基于 Swagger-PHP 的 API 文檔

前言

編寫目的

本文介紹如何使用Swagger編寫API文檔。通過閱讀本文,你可以:

  • 了解swagger是什么
  • 掌握使用swagger編寫API文檔的基本方法

第 1 章 簡介

1.1 Swagger

Swagger(絲襪哥)給人第一印象就是【最(hen)流(niu)行(bai)】,不懂Swagger咱就out了。它的官方網(wǎng)站是http://swagger.io/。

Swagger是一個(gè)簡單但功能強(qiáng)大的API表達(dá)工具。它具有地球上最大的API工具生態(tài)系統(tǒng),數(shù)以千計(jì)的開發(fā)人員,使用幾乎所有的現(xiàn)代編程語言,都在支持和使用Swagger。使用Swagger生成API,我們可以得到交互式文檔,自動(dòng)生成代碼的SDK以及API的發(fā)現(xiàn)特性等。

現(xiàn)在,Swagger已經(jīng)幫助包括Apigee, Getty圖像, Intuit, LivingSocial, McKesson, 微軟, Morningstar和PayPal等世界知名企業(yè)建立起了一套基于RESTful API的完美服務(wù)系統(tǒng)。

2.0版本已經(jīng)發(fā)布,Swagger變得更加強(qiáng)大。值得感激的是,Swagger的源碼100%開源在github。

1.2 OpenAPI 規(guī)范

OpenAPI規(guī)范是Linux基金會(huì)的一個(gè)項(xiàng)目,試圖通過定義一種用來描述API格式或API定義的語言,來規(guī)范RESTful服務(wù)開發(fā)過程。OpenAPI規(guī)范幫助我們描述一個(gè)API的基本信息,比如:

  • 有關(guān)該API的一般性描述
  • 可用路徑(/資源)
  • 在每個(gè)路徑上的可用操作(獲取/提交...)
  • 每個(gè)操作的輸入/輸出格式

目前V2.0版本的OpenAPI規(guī)范(也就是SwaggerV2.0規(guī)范)已經(jīng)發(fā)布并開源在github上。該文檔寫的非常好,結(jié)構(gòu)清晰,方便隨時(shí)查閱。關(guān)于規(guī)范的學(xué)習(xí)和理解,本文最后還有個(gè)彩蛋。

1.3 為啥要使用 OpenAPI 規(guī)范?

  • OpenAPI 規(guī)范這類 API 定義語言能夠幫助你更簡單、快速的表述 API,尤其是在 API 的設(shè)計(jì)階段作用特別突出
  • 根據(jù) OpenAPI 規(guī)范編寫的二進(jìn)制文本文件,能夠像代碼一樣用任何 VCS 工具管理起來
  • 一旦編寫完成,API文檔可以作為:
    • 需求和系統(tǒng)特性描述的根據(jù)
    • 前后臺(tái)查詢、討論、自測(cè)的基礎(chǔ)
    • 部分或者全部代碼自動(dòng)生成的根據(jù)
    • 其他重要的作用,比如開放平臺(tái)開發(fā)者的手冊(cè)...

1.4 如何編寫 API 文檔?

1.4.1 語言 JSON vs YAML

1.4.2 基于 PHP 注釋的方式

第 2 章 從零開始

這一章主要介紹 API 的基本組成部分,包括提供給 API 消費(fèi)者(所有可能訪問API的個(gè)體,下簡稱“消費(fèi)者”)的的不同 HTTP 請(qǐng)求方法、路徑,請(qǐng)求和消息體中的參數(shù),以及返回給消費(fèi)者的不同 HTTP 狀態(tài)及響應(yīng)消息體。

<?php

/**
 * @SWG\Swagger(
 *    swagger="2.0",
 *     schemes={"https"},
 *     host="tcmzapi.emao.com",
 *     basePath="/",
 *     @SWG\Info(
 *         version="1.0.0",
 *         title="淘車貓中轉(zhuǎn)庫 Api 文檔",
 *         description="淘車貓中轉(zhuǎn)庫 Api 文檔"
 *     )
 * )
 */

這個(gè)文檔的內(nèi)容分成四部分,下面分別來說明。

2.1.1 OpenAPI 規(guī)范的版本號(hào)

首先我們要通過一個(gè) swagger 屬性來聲明 OpenAPI 規(guī)范的版本。

<?php
/**
 * @SWG\Swagger(
 *     swagger="2.0"
 * )
 */

你沒看錯(cuò),是 swagger,上面已經(jīng)介紹了,OpenAPI 規(guī)范是基于 Swagger的,在未來的版本中,這個(gè)屬性可能會(huì)換成別的。 目前這個(gè)屬性的值,暫時(shí)只能填寫為 2.0。

2.1.2 API 描述信息

然后我們需要說明一下API文檔的相關(guān)信息,比如API文檔版本(注意不同于上面的規(guī)范版本)、API文檔名稱已經(jīng)可選的描述信息。

<?php
/**
 * @SWG\Info(
 *     version="1.0.0",
 *     title="淘車貓中轉(zhuǎn)庫 Api 文檔",
 *     description="淘車貓中轉(zhuǎn)庫 Api 文檔"
 * )
 */
  • version:API 文檔版本
  • title:API 文檔標(biāo)題
  • description:API文檔描述

2.1.3 API 的 URL

作為web API,一個(gè)很重要的信息就是用來給消費(fèi)者使用的根URL,可以用協(xié)議(http或者h(yuǎn)ttps)、主機(jī)名、根路徑來描述:

<?php
/**
 * @SWG\Swagger(
 *     schemes={"https"},
 *     host="tcmapi.emao.com",
 *     basePath="/v1"
 * )
 */

這這個(gè)例子中,消費(fèi)者把 https://tcmapi.emao.com/v1 作為根節(jié)點(diǎn)來訪問各種 API。因?yàn)楹途唧w環(huán)境有關(guān),不涉及 API 描述的根本內(nèi)容,所以這部分信息是可選的。

  • schemes:協(xié)議,可以是多個(gè)
  • host:主機(jī)名
  • basePath:根路徑

2.2 定義一個(gè) API 操作

如果我們要展示一組用戶信息,可以這樣描述:

<?php
/**
 * @SWG\Swagger(
 *     swagger="2.0"
 *     schemes={"https"},
 *     host="tcmapi.emao.com",
 *     basePath="/v1.0",
 *     @SWG\Info(
 *         version="1.0.0",
 *         title="淘車貓 Api 文檔",
 *         description="淘車貓 Api 文檔"
 *     )
 * )
 * @SWG\Get(
 *     path="/persons",
 *     summary="獲取一些人",
 *     description="返回包含所有人的列表。",
 *     @SWG\Response(
 *         response=200,
 *         description="一個(gè)用戶列表",
 *         @SWG\Schema(
 *             type="array",
 *             @SWG\Items(
 *                  required={"username"}
 *                  @SWG\Properties()
 *             )
 *         ),
 *     ),
 * )
 */
  • Get:請(qǐng)求的 HTTP 方法,支持 GET/POST/PUT/DELETE 等 HTTP 標(biāo)準(zhǔn)請(qǐng)求方法
  • path:請(qǐng)求的路徑
  • summary:接口簡介
  • tags:接口標(biāo)簽,可以是多個(gè)
  • description:接口描述,支持 Markdown 語法
  • operationId:操作的 ID,需要唯一

2.2.1 添加一個(gè) 路徑 (path)

我們添加一個(gè) /persons路徑,用來訪問一組用戶信息

2.2.2 在路徑中添加一個(gè) HTTP 方法

在每個(gè)路徑中,我們可以添加任意的HTTP動(dòng)詞,如GET/POST/PUT/DELETE等來操作所需要的資源。

比如需要展示一組用戶信息,我們可以在/person 路徑中添加 get 方法,同時(shí)還可以填寫一些簡單的描述信息(summary)或者說明該主主法的一段長篇大論(description)

<?php
/**
 * @SWG\Get(
 *     path="/persons",
 *     summary="獲取一些人",
 *     description="返回包含所有人的列表。"
 * )
 */

這樣一來,我們調(diào) get https://tcmapi.emao.com/v1/persons 方法就能獲取一個(gè)用戶信息列表了。

2.2.3 定義響應(yīng) (response) 類型

對(duì)于每個(gè)方法(或操作),我們都可以在響應(yīng)(responses)中添加任意的 HTTP狀態(tài)碼(比如 200 OK 或者 404 Not Found等)。這個(gè)例子中我們添加上 200 的響應(yīng):

<?php
/**
 * @SWG\Response(
 *     response=200,
 *     description="一個(gè)用戶列表"
 * )
 */

2.2.4 定義響應(yīng)內(nèi)容

get /persons這個(gè)接口返回一組用戶信息,我們通過響應(yīng)消息中的模式(schema)屬性來描述清楚具體的返回內(nèi)容。

一組用戶信息就是一個(gè)用戶信息對(duì)象的數(shù)組(array),每一個(gè)數(shù)組元素則是一個(gè)用戶信息對(duì)象(object),該對(duì)象包含三個(gè)string類型的屬性:姓氏、名字、用戶名,其中用戶名必須提供(required)。

<?php
/**
 * @SWG\Schema(
 *     type="array",
 *     @SWG\Items(
 *          required={"username"},
 *          @SWG\Property(
 *              property="firstName",
 *              type="string",
 *              description="firstName"
 *          ),
 *          @SWG\Property(
 *              property="lastName",
 *              type="string",
 *              description="lastName"
 *          ),
 *          @SWG\Property(
 *              property="username",
 *              type="string",
 *              description="username"
 *          )
 *     )
 * )
 */

2.3 定義 請(qǐng)求參數(shù) (query parameteers)

用戶太多,我們不想一股腦全部輸出出來。這個(gè)時(shí)候,分頁輸出是個(gè)不錯(cuò)的選擇,我們可以通過添加請(qǐng)求參數(shù)來實(shí)現(xiàn)。

<?php
/**
 * @SWG\Parameter(
 *     name="pageSize",
 *     in="query",
 *     description="Number of persons returned",
 *     type="integer"
 * ),
 * @SWG\Parameter(
 *     name="pageNumber",
 *     in="query",
 *     description="Page number",
 *     type="integer"
 * )
 */

2.3.1 在 get 方法中增加請(qǐng)求參數(shù)

<?php
/**
 * @SWG\Get(
 *     path="/persons",
 *     summary="獲取一些人",
 *     description="返回包含所有人的列表。",
 *     @SWG\Parameter()
 * )
 */

2.3.2 添加分頁參數(shù)

在參數(shù)列表中,我們添加兩個(gè)名字(name)分別叫做 pageSizepageNumber的整型(integer)參數(shù),并作簡單描述:

<?php
/**
 * @SWG\Get(
 *     path="/persons",
 *     summary="獲取一些人",
 *     description="返回包含所有人的列表。",
 *     @SWG\Parameter(
 *          name="pageSize",
 *          in="query",
 *          description="Number of persons returned",
 *          type="integer"
 *     ),
 *     @SWG\Parameter(
 *          name="pageNumber",
 *          in="query",
 *          description="Page number",
 *          type="integer"
 *     )
 * )
 */

這樣一來,消費(fèi)者就可以通過 get /persons?pageSize=20&pageNumber=2 來訪問第2頁的用戶信息(不超過20條)了。

2.4 定義 路徑參數(shù) (path parameter)

有時(shí)候我們想要根據(jù)用戶名來查找用戶信息,這時(shí)我們需要增加一個(gè)接口操作,比如可以添加一個(gè)類似 /persons/{username} 的操作來獲取用戶信息。注意,{username} 是在請(qǐng)求路徑中的參數(shù)。

<?php
/**
 * @SWG\Get(
 *     path="/persons/{username}",
 *     summary="獲取一些人",
 *     description="返回包含所有人的列表。",
 *     @SWG\Parameter(
 *          name="username",
 *          in="path",
 *          required="true"
 *          description="The person's username",
 *          type="string"
 *     )
 * )
 */

2.4.1 添加一個(gè) get /persons/{username} 操作

首先我們?cè)?/persons 路徑后面,增加一個(gè) /persons/{username} 的路徑,并定義一個(gè) get (操作)方法。

<?php
/**
 * @SWG\Get(
 *     path="/persons/{username}",
 *     summary="Gets a person",
 *     description="Returns a single person for its username"
 * )
 */

2.4.2 定義路徑參數(shù) username

因?yàn)?{username} 是路徑參數(shù),我們需要先像請(qǐng)求參數(shù)一樣將它添加到 parameters 屬性中,注意名稱應(yīng)該同上面大括號(hào)( { } ) 里面的名稱一致。并通過 in 這個(gè)屬性,來表示它是一個(gè)路徑(path)參數(shù)。

<?php
/**
 * @SWG\Parameter(
 *     name="username",
 *     in="path",
 *     required="true"
 *     description="The person's username",
 *     type="string"
 * )
 */

定義路徑參數(shù)時(shí)很容易出現(xiàn)的問題就是忘記:required: true,Swagger的自動(dòng)完成功能中沒有包含這個(gè)屬性定義。 如果沒有寫 require 屬性,默認(rèn)值是 false,也就是說 username 參數(shù)時(shí)可選的??墒聦?shí)上,作為路徑參數(shù),它是必需的。

2.4.3 定義響應(yīng)消息

別忘了獲取單個(gè)用戶信息也需要填寫 200 響應(yīng)消息,響應(yīng)消息體的內(nèi)容就是之前描述過的用戶信息(用戶信息列表中的一個(gè)元素):

<?php
/**
 * @SWG\Response(
 *     response=200,
 *     description="A Person",
 *     @SWG\Schema(
 *         required={"username"},
 *         @SWG\Property(
 *              property="firstName",
 *              type="string"
 *         ),
 *         @SWG\Property(
 *              property="lastName",
 *              type="string"
 *         ),
 *         @SWG\Property(
 *              property="username",
 *              type="string"
 *         )
 *     )
 * )
 */

當(dāng)然,API的提供者會(huì)對(duì) username 進(jìn)行校驗(yàn),如果查無此人,應(yīng)該返回 404 的異常狀態(tài)。所以我們?cè)偌由?404 狀態(tài)的響應(yīng):

 <?php
 /**
 * @SWG\Response(
 *     response=404,
 *     description="The Person does not exists."
 * )
 */

2.5 定義 消息體參數(shù) (body parameter)

當(dāng)我們需要添加一個(gè)用戶信息時(shí),我們需要一個(gè)能夠提供 post /persons 的API操作。

<?php
/**
 * @SWG\Post(
 *     path="/persons",
 *     summary="Creates a person",
 *     description="Adds a new person to the persons list.",
 *     @SWG\Parameter(
 *          name="person",
 *          in="body",
 *          required="true"
 *          description="The person to create.",
 *          @SWG\Schema(
 *              required={"username"},
 *              @SWG\Property(
 *                  property="firstName",
 *                  type="string"
 *              ),
 *              @SWG\Property(
 *                   property="lastName",
 *                   type="string"
 *              ),
 *              @SWG\Property(
 *                   property="username",
 *                   type="string"
 *              )
 *          )
 *     ),
 *     @SWG\Response(
 *          response="200",
 *          description="Persons succesfully created."
 *     ),
 *     @SWG\Response(
 *          response="400",
 *          description="Persons couldn't have been created."
 *     )
 * )
 */

2.5.1 添加一個(gè) post /persons 操作

首頁在 /persons 路徑下添加一個(gè) Post 操作:

<?php
/**
 * @SWG\Post(
 *     path="/persons",
 *     summary="Creates a person",
 *     description="Adds a new person to the persons list.",
 * )
 */

2.5.2 定義消息體參數(shù)

接下來我們給 post 方法添加參數(shù),通過 in 屬性顯式說明參數(shù)是在 body 中的。參數(shù)的定義參考 get /persons/{username} 的 200 響應(yīng)消息體參數(shù),也就是包含用戶的姓氏、名字、用戶名。

<?php
/**
 * @SWG\Parameter(
 *     name="person",
 *     in="body",
 *     required="true"
 *     description="The person to create.",
 *     @SWG\Schema(
 *         required={"username"},
 *         @SWG\Property(
 *             property="firstName",
 *             type="string"
 *         ),
 *         @SWG\Property(
 *              property="lastName",
 *              type="string"
 *         ),
 *         @SWG\Property(
 *              property="username",
 *              type="string"
 *         )
 *     )
 * )
 */

2.5.3 定義響應(yīng)消息

最后不要忘記定義 post 操作的響應(yīng)消息。

<?php
/**
 * @SWG\Response(
 *     response="200",
 *     description="Persons succesfully created."
 * ),
 * @SWG\Response(
 *     response="400",
 *     description="Persons couldn't have been created."
 * )
 */

第 3 章 文檔瘦身

現(xiàn)在我們已經(jīng)學(xué)會(huì)了編寫API文檔的基本方法。不過上面的例子中存在一些重復(fù),這對(duì)于程序員的嗅覺來說,就是代碼的“壞味道”。這一章我們一起學(xué)習(xí)如何通過抽取可重用的定義(definitions)來簡化API文檔。

3.1 簡化數(shù)據(jù)模型

我們認(rèn)真觀察第2章最后輸出的API文檔,很容易發(fā)現(xiàn) Person 的定義出現(xiàn)了三次,非常的不 DRY?。

現(xiàn)在,我們通過可重用的 定義 (definition)來重構(gòu)這個(gè)文檔:

<?php
/**
 * @SWG\Definition(
 *     definition="Person",
 *     type="object",
 *     required={"username"},
 *     @SWG\Property(
 *         property="firstName",
 *         type="string"
 *     ),
 *     @SWG\Property(
 *         property="lastName",
 *         type="string"
 *     ),
 *     @SWG\Property(
 *         property="username",
 *         type="string"
 *     )
 * )
 */

/**
 * @SWG\Definition(
 *     definition="Persons",
 *     type="array",
 *     @SWG\Items(ref="#/definitions/Person")
 * )
 */

文檔簡化了很多。這得益于OpenAPI規(guī)范中關(guān)于定義(definition)的章節(jié)中允許我們“一處定義,處處使用”。

3.1.1 添加 定義 (definitions) 項(xiàng)

我們首先在API文檔的尾部添加一個(gè) 定義 (definitions)項(xiàng)(其實(shí)它也可以放在文檔的任意位置,只不過大家習(xí)慣放在文檔末尾):

<?php
/**
 * @SWG\Definition()
 */

3.1.2 增加一個(gè)可重用的(對(duì)象)定義

然后我們?cè)黾右粋€(gè) Person 對(duì)象的定義:

<?php
/**
 * @SWG\Definition(
 *     definition="Person",
 *     type="object",
 *     required={"username"},
 *     @SWG\Property(
 *         name="firstName",
 *         type="string"
 *     ),
 *     @SWG\Property(
 *         name="lastName",
 *         type="string"
 *     ),
 *     @SWG\Property(
 *         name="username",
 *         type="string"
 *     )
 * )
 */

3.1.3 引用一個(gè) 定義 來增加另一個(gè) 定義

在定義項(xiàng)中,我們可以立即引用剛才定義好的 Person 來增加另一個(gè) 定義,Persons。Persons 是一個(gè) Person 對(duì)象的數(shù)組。與之前直接定義的不同之處是,我們?cè)黾恿艘粋€(gè) 引用(reference)屬性,也就是 ref 來引用 Person 。

<?php
/**
 * @SWG\Definition(
 *     definition="Persons",
 *     type="array",
 *     @SWG\Items(ref="#/definitions/Person")
 * )
 */

3.1.4 在響應(yīng)消息中使用 定義

一旦定義好了 Person ,我們可以把原來在響應(yīng)消息中相應(yīng)的定義字段替換掉。

3.1.4.1 get/persons

原來:

<?php
/**
 * @SWG\Response(
 *     response=200,
 *     description="A list of Person",
 *     @SWG\Schema(
 *         type="array",
 *         @SWG\Items(
 *              required={"username"},
 *              @SWG\Property(
 *                  property="firstName",
 *                  type="string"
 *              ),
 *              @SWG\Property(
 *                  property="lastName",
 *                  type="string"
 *              ),
 *              @SWG\Property(
 *                  property="username",
 *                  type="string"
 *              )
 *         )
 *     )
 * )
 */

現(xiàn)在:

<?php
/**
 * @SWG\Response(
 *     response=200,
 *     description="A list of Person",
 *     @SWG\Schema(
 *         type="array",
 *         @SWG\Items(ref="#/definitions/Persons")
 *     )
 * )
 */
3.1.4.2 get/persons/{username}

原來:

<?php
/**
 * @SWG\Response(
 *     response=200,
 *     description="A Person",
 *     @SWG\Schema(
 *          required={"username"},
 *          @SWG\Property(
 *              property="firstName",
 *              type="string"
 *          ),
 *          @SWG\Property(
 *              property="lastName",
 *              type="string"
 *          ),
 *          @SWG\Property(
 *              property="username",
 *              type="string"
 *          )
 *     )
 * )
 */

現(xiàn)在:

<?php
/**
 * @SWG\Response(
 *     response=200,
 *     description="A Person",
 *     @SWG\Schema(ref="#/definitions/Person")
 * )
 */

3.1.5 在參數(shù)中使用 定義

不僅僅在消息中可以使用 定義,在參數(shù)中也可以使用。

3.1.5.1 post /persons

原來:

<?php
/**
 * @SWG\Post(
 *     path="/persons",
 *     summary="Creates a person",
 *     description="Adds a new person to the persons list.",
 *     @SWG\Parameter(
 *          name="person",
 *          in="body",
 *          required="true"
 *          description="The person to create.",
 *          @SWG\Schema(
 *              required={"username"},
 *              @SWG\Property(
 *                  property="firstName",
 *                  type="string"
 *              ),
 *              @SWG\Property(
 *                   property="lastName",
 *                   type="string"
 *              ),
 *              @SWG\Property(
 *                   property="username",
 *                   type="string"
 *              )
 *          )
 *     )
 * )
 */

現(xiàn)在:

<?php
/**
 * @SWG\Post(
 *     path="/persons",
 *     summary="Creates a person",
 *     description="Adds a new person to the persons list.",
 *     @SWG\Parameter(
 *          name="person",
 *          in="body",
 *          required="true"
 *          description="The person to create.",
 *          @SWG\Schema(ref="#/definitions/Person")
 *     )
 * )
 */

3.2 簡化響應(yīng)消息

我們看到了 引用 ($ref)的作用,接下來我們?cè)侔阉玫巾憫?yīng)消息的定義中:

3.2.1 定義可重用的HTTP 500 響應(yīng)

發(fā)生HTTP 500錯(cuò)誤時(shí),假如我們希望每一個(gè)API操作都返回一個(gè)帶有錯(cuò)誤碼(error code)和描述信息(message)的響應(yīng),我們可以這樣做:

<?php
/**
 * @SWG\Response(
 *     response="500",
 *     description="An unexpected error occured.",
 *     @SWG\schema(
 *         @SWG\Property(
 *             property="code",
 *             type="string"
 *         ),
 *         @SWG\Property(
 *             property="message",
 *             type="string"
 *         )
 *     )
 * )
 */

3.2.2 增加一個(gè) Error 定義

按照“一處定義、處處引用”的原則,我們可以在定義項(xiàng)中增加 Error 的定義:

<?php
/**
 * @SWG\Definition(
 *     definition="Error",
 *     @SWG\Property(
 *         property="code",
 *         type="string"
 *     ),
 *     @SWG\Property(
 *         property="message",
 *         type="string"
 *     )
 * )
 */

而且我們也學(xué)會(huì)了使用 引用($ref),所以我們可以這樣寫:

<?php
/**
 * @SWG\Response(
 *     response="500",
 *     description="An unexpected error occured.",
 *     @SWG\schema(ref="#/definitions/Error")
 * )
 */

3.2.3 定義一個(gè)可重用的響應(yīng)消息

上面的文檔中,還是有一些重復(fù)的內(nèi)容。我們可以根據(jù) OpenAPI 規(guī)范中的 responses 章節(jié)的描述,通過定義一個(gè)可重用的響應(yīng)消息,來進(jìn)一步簡化文檔。

<?php
/**
 * @SWG\Response(
 *     response="Standard500ErrorResponse",
 *     description="An unexpected error occured.",
 *     @SWG\schema(ref="#/definitions/Error")
 * )
 */

注意:響應(yīng)消息中引用了 Error 的定義。

3.2.4 使用已定義的響應(yīng)消息

我們還是通過 引用($ref)來使用一個(gè)已經(jīng)定義好的響應(yīng)消息,比如:

3.2.4.1 get /users
<?php
/**
 * @SWG\Response(
 *     response="200",
 *     description="A list of Person",
 *     @SWG\schema(ref="#/definitions/Persons")
 * ),
 * @SWG\Response(
 *     response="500",
 *     ref="#/responses/Standard500ErrorResponse"
 * )
 */

略去一部份不重要的。

第 4 章 深入了解一下

通過前面的練習(xí),我們可以寫出一篇結(jié)構(gòu)清晰、內(nèi)容精煉的API文檔了??墒?OpenAPI 規(guī)范還給我們提供了更多的便利和驚喜,等著我們?nèi)チ私夂驼莆?。這一章主要介紹用于定義屬性和數(shù)據(jù)模型的高級(jí)方法。

4.1 私人定制

使用 JSON Schema Draft 4,我們可以定義任意類型的各種屬性,舉例說明。

4.1.1 定符串 (strings) 長度和格式

當(dāng)定義個(gè)字符串屬性時(shí),我們可以定制它的長度及格式:

屬性 類型 描述
minLength number 字符串最小長度
maxLength number 字符串最大長度
pattern string 正則表達(dá)式

如果我們規(guī)定用戶名是長度介于8~64,而且只能由小寫字母和數(shù)字來構(gòu)成,那么我們可以這樣寫:

<?php
/**
 * @SWG\Property(
 *     property="username",
 *     type="string",
 *     pattern="[a-z0-9]{8,64}",
 *     minLength="8",
 *     maxLength="64"
 * )
 */

4.1.2 日期和時(shí)間

日期和時(shí)間的處理參考 RFC 3339 ,我們唯一要做的就是寫對(duì)格式:

格式 屬性包含內(nèi)容 屬性示例
date ISO8601 full-date 2016-04-01
dateTime ISO8601 date-time 2016-04-16T16:06:05Z

如果我們?cè)?Person 的定義中增加 生日上次登錄時(shí)間 時(shí)間戳,我們可以這樣寫:

<?php
/**
 * @SWG\Property(
 *     property="dateOfBirth",
 *     type="string",
 *     format="date"
 * ),
 * @SWG\Property(
 *     property="lastTimeOnline",
 *     type="string",
 *     format="dateTime"
 * )
 */

4.1.3 數(shù)字類型與范圍

當(dāng)我們定義一個(gè)數(shù)字類型的屬性時(shí),我們可以規(guī)定它是一個(gè)整型、長型、浮點(diǎn)型或者雙浮點(diǎn)型。

名稱 類型 格式
integer integer int32
long integer int64
float number float
double number double

和字符串一樣,我們也可以定義數(shù)字屬性的范圍,比如:

屬性 類型 描述
minimum number 最小值
maximum number 最大值
exclusiveMinimum boolean 數(shù)值必須 > 最小值
exclusiveMaximum boolean 數(shù)值必須 < 最大值
multipleOf number 數(shù)值必須是 multipleOf 的整數(shù)倍

如果我們規(guī)定 pageSize 必須是整數(shù),必須 > 0 且 <=100,還必須是 10 的整數(shù)倍,可以這樣寫:

<?php
/**
 * @SWG\Parameter(
 *     name="pageSize",
 *     in="query"
 *     description="Number of persons returned",
 *     type="integer",
 *     format="int32",
 *     minimum: 0,
 *     exclusiveMinimum: true,
 *     maximum: 100,
 *     exclusiveMaximum: false,
 *     multipleOf: 10
 * )
 */

4.1.4 枚舉類型

我們還可以定義枚舉類型,比如定義 Error 時(shí),我們可以這樣寫:

<?php
/**
 * @SWG\Property(
 *     property="code",
 *     type="string",
 *     enum={"DBERR", "NTERR", "UNERR"}
 * )
 */

code 的值只能從三個(gè)枚舉值中選擇。

4.1.5 數(shù)值的大小和唯一性

數(shù)字的大小和唯一性通過下面這些屬性來定義:

屬性 類型 描述
minItems number 數(shù)值中的最小元素個(gè)數(shù)
maxItem number 數(shù)值中的最大元素個(gè)數(shù)
uniqueItems boolean 標(biāo)示數(shù)組中的元素是否唯一

比如我們定義一個(gè)用戶數(shù)組 Persons,希望返回的用戶信息條數(shù)介于10~100之間,而且不能有重復(fù)的用戶信息,我們可以這樣寫:

<?php
/**
 * @SWG\Property(
 *     property="Persons",
 *     @SWG\Items(
 *         type="array",
 *         minItems="10",
 *         maxItems="100",
 *         uniqueItems="true",
 *         ref="#/definitions/Person"
 *     )
 * )
 */

4.1.6 二進(jìn)制數(shù)據(jù)

可以用 string 類型來表示二進(jìn)制數(shù)據(jù):

格式 屬性包含
byte Base64編碼字符
binary Base64任意十進(jìn)制的數(shù)據(jù)序列字符

比如我們需要在用戶信息中增加一個(gè)頭像屬性(avatarBase64PNG)用base64編碼的PNG圖片來表示,可以這樣寫:

<?php
/**
 * @SWG\Property(
 *     property="avatarBase64PNG",
 *     type="string",
 *     format="byte"
 * )
 */

4.2 高級(jí)數(shù)據(jù)定義

4.2.1 讀寫操作同一定義的數(shù)據(jù)

有時(shí)候我們讀取資源信息的內(nèi)容會(huì)比我們寫入資源信息的內(nèi)容(屬性)更多,這很常見。是不是意味著我們必須專門為讀取資源和寫入資源分別定義不同的數(shù)據(jù)模型呢?幸運(yùn)的是,OpenAPI 規(guī)范中提供了 readOnly 字段來幫我們解決整問題。比如:

<?php
/**
 * @SWG\Property(
 *     property="lastTimeOnline",
 *     type="string",
 *     format="dateTime",
 *     readOnly="true"
 * )
 */

上面這個(gè)例子中,上次在線時(shí)間(lastTimeOnline )是 Person 的一個(gè)屬性,我們獲取用戶信息時(shí)需要這個(gè)屬性。但是很明顯,在創(chuàng)建用戶時(shí),我們不能把這個(gè)屬性 post 到服務(wù)器。于是我們可以把它標(biāo)記為 readOnly。

4.2.2 組合定義確保一致性

一致性設(shè)計(jì)是在編寫API文檔時(shí)需要重點(diǎn)考慮的問題。比如我們?cè)讷@取一組用戶信息時(shí),需要同時(shí)獲取頁面信息(totalItems, totalPage, pageSize, currentPage)等,而且這些信息 必須 在根節(jié)點(diǎn)上。

怎么辦呢?首先想到的做法就是:

<?php
/**
 * @SWG\Definition(
 *     definition="PagedPersonsV1",
 *     @SWG\Property(
 *          property="items",
 *          type="array",
 *          @SWG\Items(ref="#/definitions/Person")
 *     ),
 *     @SWG\Property(
 *          property="totalItems",
 *          type="integer"
 *     ),
 *     @SWG\Property(
 *          property="totalPages",
 *          type="integer"
 *     ),
 *     @SWG\Property(
 *          property="pageSize",
 *          type="integer"
 *     ),
 *     @SWG\Property(
 *          property="currentPage",
 *          type="integer"
 *     )
 * )
 */

如果其他API操作也需要這些 頁面信息,那就意味著這些屬性必須一遍又一遍的定義。不僅重復(fù)體力勞動(dòng),而且還很危險(xiǎn):比如忘記了其中的一兩個(gè)屬性,或者需要添加一個(gè)新的屬性進(jìn)來,那就是霰彈式的修改,想想都很悲壯。

稍微好一點(diǎn)的做法,就是根據(jù)前面學(xué)習(xí)的內(nèi)容,把這幾個(gè)屬性抽取出來,建立一個(gè) Paging 模型,“一處定義、處處使用”:

<?php
/**
 * @SWG\Definition(
 *     definition="PagedPersonsV2",
 *     @SWG\Property(
 *          property="items",
 *          type="array",
 *          @SWG\Items(ref="#/definitions/Person")
 *     ),
 *     @SWG\Property(
 *          property="Paging",
 *          @SWG\Items(ref="#/definitions/Paging")
 *     )
 * ),
 * @SWG\Definition(
 *     definition="Paging",
 *     @SWG\Property(
 *          property="totalItems",
 *          type="integer"
 *     ),
 *     @SWG\Property(
 *          property="totalPages",
 *          type="integer"
 *     ),
 *     @SWG\Property(
 *          property="pageSize",
 *          type="integer"
 *     ),
 *     @SWG\Property(
 *          property="currentPage",
 *          type="integer"
 *     )
 * )
 */

但是,頁面屬性都不再位于 根節(jié)點(diǎn)!與我們前面設(shè)定的要求不一樣了。怎么破?

JSON Schema v4 property中定義的 allOf,能幫我們解圍:

<?php
/**
 * @SWG\Definition(
 *     definition="PagedPersons",
 *     allOf={
            @SWG\Schema(ref="#/definitions/Persons"),
 *          @SWG\Schema(ref="#/definitions/Paging"),
 *     }
 * )
 */

上面這個(gè)例子表示,PagedPersons 根節(jié)點(diǎn)下,具有將 Persons 和 Paging 展開 后的全部屬性。

allOf 同樣可以使用行內(nèi)的數(shù)據(jù)定義,比如

<?php
/**
 * @SWG\Definition(
 *     definition="PagedCollectingItems",
 *     allOf={
            @SWG\Property(
 *              property="items",
 *              type="array",
 *              minItems="10",
 *              maxItems="100",
 *              uniqueItems="true",
 *              @SWG\Items(ref="#/definitions/CollectingItem")
 *          ),
 *          @SWG\Schema(ref="#/definitions/Paging"),
 *     }
 * )
 */

4.2.3 數(shù)據(jù)模型的繼承(TODO)

目前各工具支持程度不高,待續(xù)

第 5 章 輸入輸出模型

這一章主要介紹如何定義高度精確化的參數(shù)和響應(yīng)消息等。

5.1 高級(jí)參數(shù)定義

5.1.1 必帶參數(shù)和可選參數(shù)

我們已經(jīng)知道使用關(guān)鍵字 required 來定義一個(gè)必帶參數(shù)。

5.1.1.1 定義必帶參數(shù)和可選參數(shù)

在一個(gè)參數(shù)中,required 是一個(gè) boolean 型的可選值。它的默認(rèn)值是 false 。

比如在某個(gè)操作中,username 是必填參數(shù):

<?php
/**
 * @SWG\Parameter(
 *     name="username",
 *     in="path",
 *     required="true"
 *     description="The person's username",
 *     type="string"
 * )
 */
5.1.1.2 定義必帶屬性和可選屬性

根據(jù)定義,required 是一個(gè)字符串列表,列表中包含各必帶參數(shù)名。如果某個(gè)參數(shù)在這張列表中找不到,那就說明它不是必帶參數(shù)。如果沒有定義required ,就說明所有參數(shù)都是可選。如果 required 定義在一個(gè)HTTP請(qǐng)求上,這說明所有的請(qǐng)求參數(shù)都是必填。

在 POST 、persons 中有 Person 的定義,在這里 username 這個(gè)屬性是必帶的,我們可以指定它為 required ,其他非必帶字段則不指定:

<?php
/**
 * @SWG\Items(
 *     required={"username"},
 *     @SWG\Property(
 *         property="firstName",
 *         type="string"
 *     ),
 *     @SWG\Property(
 *         property="lastName",
 *         type="string"
 *     ),
 *     @SWG\Property(
 *         property="username",
 *         type="string"
 *     )
 * )
 */

5.1.2 帶默認(rèn)值的參數(shù)

通過關(guān)鍵字 default,我們可以定義一個(gè)參數(shù)的默認(rèn)值。當(dāng)這個(gè)參數(shù)不可得(請(qǐng)求未帶或者服務(wù)器未返回)時(shí),這個(gè)參數(shù)就取默認(rèn)值。因此設(shè)定了某個(gè)參數(shù)的默認(rèn)值后,它是否 required 就沒意義了。

5.1.2.1 定義參數(shù)的默認(rèn)值

我們定義參數(shù) pageSize 的默認(rèn)值為 20 ,那么如果請(qǐng)求時(shí)沒有填寫 pageSize ,服務(wù)器也會(huì)默認(rèn)返回 20 個(gè)元素。

<?php
/**
 * @SWG\Parameter(
 *     name="pageSize",
 *     in="query"
 *     description="Number of persons returned",
 *     type="integer",
 *     format="int32",
 *     minimum="0",
 *     exclusiveMinimum="true",
 *     maximum="100",
 *     exclusiveMaximum="false",
 *     multipleOf="10",
 *     default="20"
 * )
 */
5.1.2.2 定義屬性的默認(rèn)值

同參數(shù),使用關(guān)鍵字 default 即可。

5.1.3 帶空值的參數(shù)

在 GET /persons 時(shí),如果我們想添加一個(gè)參數(shù)來過濾“是否通過實(shí)名認(rèn)證”的用戶,應(yīng)該怎么做呢?首先想到的是這樣:GET /persons?page=2&includeVerifiedUsers=true ,問題是 includeVerifiedUsers 語義已經(jīng)如此清晰,而讓 “=true”顯得很多余。我們能不能直接用:GET /persons?page=2&includeVerifiedUsers 呢?

要做到這種寫法,我們需要一個(gè)關(guān)鍵字 allowEmptyValue 。我們定義 includeVerifiedUsers 時(shí)允許它為空。那么如果我們請(qǐng)求 GET /persons?page=2&includeVerifiedUsers 則表示需要過濾“實(shí)名認(rèn)證”用戶,如果我們直接請(qǐng)求 GET /persons?page=2 則表示不過濾:

<?php
/**
 * @SWG\Parameter(
 *     name="includeNonVerifiedUsers",
 *     in="query"
 *     type="boolean",
 *     default="false",
 *     allowEmptyValue="true"
 * )
 */

5.1.4 參數(shù)組

設(shè)計(jì)API的時(shí)候,我們經(jīng)常會(huì)遇到在 GET 請(qǐng)求中需要攜帶一組請(qǐng)求參數(shù)的情況。如何在API文檔章呈現(xiàn)呢?很簡單,我們只需要設(shè)定 參數(shù)類型(type)array,并選擇合適的 組合格式(collectionFormat) 就行了。

組合格式 描述
csv (default value) Comma separated values(逗號(hào)分隔) foo,bar
ssv Space separated values(空格分隔) foo bar
tsv Tab separated values(反斜杠分隔) foo\bar
pipes Pipes separated values(豎線分隔) `foo bar`
multi 單屬性可以取多個(gè)值,比如 foo=bar&foo=baz. 只適用于查詢參數(shù)和表單參數(shù)。

比如我們想根據(jù)多種參數(shù)(username , firstname , lastname , lastTimeOnline )等來對(duì) Person 進(jìn)行帶排序的查詢。我們需要一個(gè)這樣的API請(qǐng)求: GET /persons?sort=-lastTimeOnline|+firtname|+lastname 。用于排序的參數(shù)是 sort ,+表示升序,-表示降序。

相應(yīng)的API文檔,可以這樣寫:

<?php
/**
 * @SWG\Parameter(
 *     name="sort",
 *     in="query"
 *     type="array",
 *     uniqueItems=true,
 *     minItems=1,
 *     maxItems=3,
 *     collectionFormat="pipes",
 *     @SWG\items(
 *         type="string",
 *         pattern="[-+](username|lastTimeOnline|firstName|lastName)",
 *     )
 * )
 */

現(xiàn)在我們就能搞定 GET /persons?sort=-lastTimeOnline|+firtname|+lastname 這種請(qǐng)求了。當(dāng)然,我們還可以指定排序的默認(rèn)值,錦上添花。

<?php
/**
 * @SWG\Parameter(
 *     name="sort",
 *     in="query"
 *     type="array",
 *     uniqueItems=true,
 *     minItems=1,
 *     maxItems=3,
 *     collectionFormat="pipes",
 *     @SWG\items(
 *         type="string",
 *         pattern="[-+](username|lastTimeOnline|firstName|lastName)",
 *     ),
 *     default={"-lastTimeOnline", "+username"}
 * )
 */

5.1.5 消息頭 (Header) 參數(shù)

參數(shù),按照位置來分,不僅僅包含路徑參數(shù)、請(qǐng)求參數(shù)和消息體參數(shù),還包括消息頭參數(shù)和表單參數(shù)等。比如我們可以在HTTP請(qǐng)求的消息頭上加一個(gè) User-Agent (用于跟蹤、調(diào)試或者其他),可以這樣定義它:

<?php
/**
 * @SWG\Parameter(
 *      parameter="userAgent",
 *      name="User-Agent",
 *      type="string",
 *      in="header",
 *      required=true
 *  )
 */

然后像使用其他參數(shù)一樣使用它:

<?php
/**
 * @SWG\Parameter(ref="#/parameters/userAgent")
 */

5.1.6 表單參數(shù)

有些 js-less-browser 的老瀏覽器不支持 POST JSON數(shù)據(jù),比如在創(chuàng)建用戶時(shí),只能夠以這樣個(gè)格式請(qǐng)求:

POST /js-less-persons

username=apihandyman&firstname=API&lastname=Handyman

沒有問題,絲襪哥可以搞定。我們只需要把各個(gè)屬性的 in 關(guān)鍵字定義為formData ,然后設(shè)置 consumes 的媒體類型為 application/x-www-form-urlencoded 即可。

<?php
/**
 * @SWG\Post(
 *     path="/persons",
 *     summary="Creates a person",
 *     description="For JS-less partners",
 *     consumes={"application/x-www-form-urlencoded"},
 *     produces={"text/html"},
 *     @SWG\parameter(
 *         name="username",
 *         in="formData",
 *         required="true",
 *         pattern="[a-z0-9]{8,64}",
 *         minLength=8,
 *         maxLength=64,
 *         type="string"
 *
 *      )
 * )
 */

5.1.7 文件參數(shù)

當(dāng)我們要處理一個(gè)請(qǐng)求,輸入類型是 文件 時(shí),我們需要:

  • 使用 multipart/form-data 媒體類型;

  • 設(shè)置參數(shù)的 in 關(guān)鍵字為 formData;

  • 設(shè)置參數(shù)的 類型(type) 為 file。

比如:

<?php
/**
 * @SWG\Post(
 *     path="/images",
 *     summary="Uploads an image",
 *     consumes={"multipart/form-data"},
 *     @SWG\Parameter(
 *         name="image",
 *         in="formData",
 *         type="file"
 *     )
 *     @SWG\Response(
 *         response="200",
 *         description="Image's ID",
 *         @SWG\Schema(
 *             @SWG\Property(
 *                  property="imageId",
 *                  type="string"
 *             )
 *         )
 *     )
 * )
 */

有時(shí)候我們想限定輸入文件的類型(后綴),很不幸的是,根據(jù)現(xiàn)在V2.0的規(guī)范暫時(shí)還做不到?

5.1.8 參數(shù)的媒體類型

一個(gè) API 可以消費(fèi)各種不同的媒體類型,比如說最常見的是 application/json 類型的數(shù)據(jù),當(dāng)然這不是 API 唯一支持的類型。我們可以在 文檔的根節(jié)點(diǎn) 或者 一個(gè)操作的根節(jié)點(diǎn) 下添加關(guān)鍵字 consumes,來定義這個(gè)操作能夠消費(fèi)的媒體類型。

比如我們的API全部都接受JSON和YAML的數(shù)據(jù),那我們可以在文檔的根節(jié)點(diǎn)下添加:

<?php
/**
 * @SWG\Swagger(
 *     consumes={"application/json", "application/x-yaml"}
 * )
 */

如果某個(gè)操作(比如上傳圖片的操作)很特殊,它可以通過自己添加 consumes來覆蓋全局設(shè)置:

<?php
/**
 * @SWG\Post(
 *     path="/images",
 *     summary="Uploads an image",
 *     consumes={"multipart/form-data"},
 *     @SWG\Parameter(
 *         name="image",
 *         in="formData",
 *         type="file"
 *     )
 *     @SWG\Response(
 *         response="200",
 *         description="Image's ID",
 *         @SWG\Schema(
 *             @SWG\Property(
 *                  name="imageId",
 *                  type="string"
 *             )
 *         )
 *     )
 * )
 */

5.2 高級(jí)響應(yīng)消息定義

5.2.1 不帶消息體的響應(yīng)消息

不帶消息體的響應(yīng)很常見,比如HTTP 204 狀態(tài)響應(yīng)本身就表示服務(wù)器返回不帶任何消息內(nèi)容的成功消息。

要定義一個(gè)不帶消息體的響應(yīng)很簡單,我們只需要寫響應(yīng)狀態(tài)和描述就行了:

<?php
/**
 * @SWG\Response(
 *     response="204",
 *     description="Person succesfully created."
 * )
 */

5.2.2 響應(yīng)消息中的必帶參數(shù)和可選參數(shù)

與請(qǐng)求消息中類似,我們使用 required 參數(shù)來表示,比如請(qǐng)求一個(gè)用戶信息時(shí), 服務(wù)器必須返回username。

5.2.3 響應(yīng)消息頭

API 的返回結(jié)果不僅僅體現(xiàn)下 HTTP 狀態(tài)和響應(yīng)消息體,還可以在響應(yīng)消息頭上做文章。比如我們可以限定一個(gè)API的使用次數(shù)和使用時(shí)間段,在響應(yīng)消息頭中,增加一個(gè)屬性 X-Rate-Limit-Remaining 來表示API可調(diào)用的剩余次數(shù),增加另一個(gè)屬性 X-Rate-Limit-Reset 來表示 API 的有效截止時(shí)間。

<?php
/**
 * @SWG\Response(
 *     response="204",
 *     description="Person succesfully created."
 *     @SWG\Header(
 *       header="X-Rate-Limit-Remaining",
 *       type="integer",
 *       format="int32"
 *     ),
 *     @SWG\Header(
 *       header="X-Rate-Limit-Reset",
 *       type="string",
 *       format="date-time"
 *     )
 * )
 */

5.2.4 默認(rèn)響應(yīng)消息

我們?cè)诙x響應(yīng)消息時(shí),通常會(huì)列舉不同的HTTP狀態(tài)結(jié)果。如果有些狀態(tài)不在我們API文檔的定義范圍(比如服務(wù)器需要返回 993 的狀態(tài)),該怎么處理呢?這時(shí)需要通過關(guān)鍵字 default 來定義一個(gè)默認(rèn)響應(yīng)消息,用于各種 定義之外 的狀態(tài)響應(yīng),比如:

<?php
/**
 * @SWG\Response(
 *     response="default",
 *     description="default response"
 * )
 */

目前這個(gè)配置也不支持“一次定義,處處使用” 。?

5.2.5 響應(yīng)消息的媒體類型

與請(qǐng)求消息一樣,我們也可以定義響應(yīng)消息所支持的媒體類型,不同的是我們要用到關(guān)鍵字 produces(與請(qǐng)求消息中的 consumes 相對(duì),由此可見,API 文檔描述的主體是服務(wù)提供者)。

比如,我們可以在文檔的根路徑下全局設(shè)置:

<?php
/**
 * @SWG\Swagger(
 *     produces={"application/json", "application/x-yaml"}
 * )
 */

也可以在某個(gè)操作的根路徑下覆蓋設(shè)置。

5.3 定義某個(gè)參數(shù)只存在于響應(yīng)消息中

如前章節(jié)4.2.1中已經(jīng)提到的,定義一個(gè)對(duì)象,其中某個(gè)屬性我們只希望在響應(yīng)消息中攜帶,而不希望在請(qǐng)求消息中攜帶,應(yīng)該用 readOnly 關(guān)鍵字來表示

第 6 章 不要讓 API 裸奔

第 7 章 讓文檔的可讀性更好

7.1 分類標(biāo)簽 (Tags)

通過關(guān)鍵字 tags 我們可以對(duì)文檔中接口進(jìn)行歸類,tags 的本質(zhì)是一個(gè)字符串列表。tags 定義在文檔的根路徑下。

7.1.1 單標(biāo)簽

比如說 GET /persons 屬于用戶(Person) 這個(gè)分類的,那么我們可以給它貼個(gè)標(biāo)簽:

<?php
/**
 * @SWG\Get(
 *     path="/persons",
 *     summary="Gets some persons",
 *     description="Returns a list containing all persons. The list supports paging.",
 *     operationId="searchUsers",
 *     @SWG\Parameter(ref="#/parameters/userAgent"),
 *     tags={"Persons"}
 * )
 */

7.1.2 多標(biāo)簽

一個(gè)操作也可以同時(shí)貼幾個(gè)標(biāo)簽,比如:

<?php
/**
 * @SWG\Get(
 *     path="/js-less-consumer-persons",
 *     summary="Creates a person",
 *     description="For JS-less partners",
 *     operationId="createUserJS",
 *     @SWG\Parameter(ref="#/parameters/userAgent"),
 *     deprecated=true
 *     tags={"JSLess", "Persons"}
 * )
 */

貼上標(biāo)簽后,在Swagger Editor和Swagger UI中能夠自動(dòng)歸類,我們可以按照標(biāo)簽來篩選接口,試試吧?

7.2 無處不在的描述文字(Descriptions)

description 這個(gè)屬性幾乎是無處不在,為了提高文檔的可讀性,我們應(yīng)該在必要的地方都加上描述文字。

7.2.1 安全項(xiàng)的描述

7.2.2 模式 (Schema) 的描述

每一種模式(Schema),都會(huì)有一個(gè)標(biāo)題(title)和一段描述,比如:

<?php
/**
 * @SWG\Definition(
 *     definition="Person",
 *     title="Human",
 *     description="A person which can be the user itself or one of his friend"
 * )
 */

7.2.3 屬性的描述

比如:

<?php
/**
 * @SWG\Property(
 *     property="firstName",
 *     description="first name",
 *     type="string"
 * )
 */

7.2.4 參數(shù)的描述

比如:

/**
 * @SWG\Parameter(
 *      parameter="username",
 *      name="username",
 *      type="string",
 *      in="path",
 *      required=true,
 *     description="The person's username"
 *  )
 */

7.2.5 操作的概述 (summary)、描述和操作 ID (operationId)

一個(gè)操作(Operation)通常都會(huì)包含概述和描述信息。而且我們還可以添加一個(gè)關(guān)鍵字 operationId,這個(gè)關(guān)鍵字通常用來指示服務(wù)提供者對(duì)這個(gè)操作的 處理函數(shù) 的函數(shù)名。比如:

<?php
/**
 * @SWG\Get(
 *     path="/persons",
 *     summary="Gets some persons",
 *     description="Returns a list containing all persons. The list supports paging.",
 *     operationId="searchUsers",
 *     @SWG\Parameter(ref="#/parameters/userAgent"),
 *     tags={"Persons"}
 * )
 */

7.2.6 響應(yīng)消息的描述

<?php
/**
 * @SWG\Response(
 *     response=200,
 *     description="A list of Person"
 * )
 */

7.2.7 響應(yīng)消息頭的描述

7.2.8 標(biāo)簽的描述

我們?cè)?API 文檔的根路徑下添加了 tags 的定義,對(duì)于其中的每一個(gè)標(biāo)簽,我們都可以添加描述信息:

<?php
/**
 * @SWG\Tag(
 *     names="Persons",
 *     description="Everything you need to handle users and friends"
 * )
 */

7.3 在描述中使用 Markdown 語法

在絕大部份的 description 中,我們可以使用 GFM (Github Flavored Markdown)語法。

7.3.1 多行描述

使用符號(hào) | 然后在新行中打一個(gè)tab(注意:YAML的tab是兩個(gè)空格 ),就可以編輯多行描述,比如:

<?php
/**
 * @SWG\Tag(
 *     names="Persons",
 *     description="|
 *   Returns a list containing all items this person is looking for.
The list supports paging.
 *     "
 * )
 */

7.3.2 簡單使用GFM

比如我們要強(qiáng)調(diào),可以這樣寫:

7.3.3 帶信息組的描述

7.3.4 帶代碼的描述

7.4 示例數(shù)據(jù) (Examples)

我們已經(jīng)知道了用Schema來描述參數(shù)和屬性,有的時(shí)候,用示例數(shù)據(jù)更有表現(xiàn)了。我們可以使用關(guān)鍵字example來給原子屬性或者對(duì)象添加示例數(shù)據(jù)。

7.4.1 原子屬性的示例數(shù)據(jù)

<?php
/**
 * @SWG\Property(
 *     property="firstName",
 *     description="first name",
 *     type="string",
 *     example="John"
 * )
 */

7.4.2 對(duì)象屬性的示例數(shù)據(jù)

待補(bǔ)充

7.4.3 定義的示例數(shù)據(jù)

待補(bǔ)充

7.4.4 響應(yīng)消息的示例數(shù)據(jù)

待補(bǔ)充

7.4.5 示例數(shù)據(jù)的優(yōu)先級(jí)

如果我們?cè)诟鱾€(gè)級(jí)別(比如參數(shù)、對(duì)象、定義、響應(yīng)消息)都添加了示例數(shù)據(jù)。支持 OpenAPI 規(guī)范的各解析工具 都是最高級(jí)別 的定義為準(zhǔn)。

7.5 標(biāo)記為棄用

我們可以通過關(guān)鍵字 deprecated 置為 true 來標(biāo)記接口的 棄用 狀態(tài),比如:

<?php
/**
 * @SWG\Get(
 *     path="/js-less-consumer-persons",
 *     summary="Creates a person",
 *     description="For JS-less partners",
 *     operationId="createUserJS",
 *     @SWG\Parameter(ref="#/parameters/userAgent"),
 *     deprecated=true
 *     tags={"JSLess", "Persons"}
 * )
 */

7.6 鏈接到外部文檔

一般來說,項(xiàng)目中不光只有一篇API文檔,還應(yīng)該有些描述application key,測(cè)試用例,操作鏈以及其他內(nèi)容的文檔,這些文檔一般是單獨(dú)成篇的。如果在描述某個(gè)接口時(shí),我們想鏈接這些文檔,可以通過關(guān)鍵字externalDoc 來添加,例如:

<?php
/**
 * @SWG\ExternalDocumentation(
 *     description="Complete documentation describing how to use this API",
 *     url="http://doc.simple.api/"
 * )
 */

第 8 章 分而治之

根據(jù)前面幾張的知識(shí),我們已經(jīng)可以輕松的構(gòu)建一個(gè)復(fù)雜的API文檔了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong閱讀 22,942評(píng)論 1 92
  • 去年有段時(shí)間得空,就把谷歌GAE的API權(quán)威指南看了一遍,收獲頗豐,特別是在自己幾乎獨(dú)立開發(fā)了公司的云數(shù)據(jù)中心之后...
    騎單車的勛爵閱讀 21,116評(píng)論 0 41
  • 需求: 為客戶端同事寫接口文檔的各位后端同學(xué),已經(jīng)在各種場合回憶了使用自動(dòng)化文檔工具前手寫文檔的血淚史.我的故事卻...
    _Lyux閱讀 4,937評(píng)論 0 2
  • 2016你好,2016再見! 2016是我從學(xué)校出來的第一年,有過快樂,也有過辛酸 記得3月份我走進(jìn)我實(shí)習(xí)的班級(jí)中...
    0a7f5205f636閱讀 210評(píng)論 1 1

友情鏈接更多精彩內(nèi)容