大部分 Web 應用程序都支持 RESTful API,但不同於 SOAP API——REST API 依賴於 HTTP 方法,缺少與 Web 服務描述語言(Web Services Description Language,WSDL)類似的語言來定義使用者與提供者之間的請求和響應結構。由於沒有充分的合同服務,許多 REST API 提供者使用 Microsoft Word 文檔或維基頁面來記錄 API 用法。這些格式使協作和文檔版本控制變得很困難,尤其對於有許多 API 或資源的應用程序,或者在 API 采用迭代式開發方式時。這些文檔類型在集成到自動化測試應用程序中時變得更難。
開源 Swagger 框架幫助 API 使用者和開發人員糾正了這些問題。該框架為創建 JSON 或 YAML(JSON 的一個人性化的超集)格式的 RESTful API 文檔提供了 OpenAPI 規范(以前稱為 Swagger 規范)。Swagger 文檔可由各種編程語言處理,可在軟件開發周期中簽入源代碼控制系統中,以便進行版本管理。
但是 Swagger 本身也有不足之處。當我們使用該框架記錄自己的 API 時,會發現我們的文檔需求與 Swagger 的基本功能之間存在空白。我們將介紹我們在文檔化過程中遇到的挑戰,並展示如何通過以下方法解決它們:
- 實現 Swagger 擴展
- 簡化 Swagger 的功能來聚合文檔
- 創建一個輸出 Swagger 文檔為 HTML 頁面的工具
我們開發的解決方案可通過下載獲得(參見“下載”)。您可以修改我們的示例,以便使用 Swagger 為您自己的 RESTful API 創建文檔,並(使用您在本文中學到的技術)創建您自己的 Swagger 定制化。
使用 Swagger
一些 Swagger 編輯工具可幫助您輕松地創建 API 文檔,確保它們遵守 OpenAPI 規范。舉例而言,通過使用 Swagger Editor,您可以創建或導入 API 文檔,並在一個交互式環境中瀏覽它。右側的顯示窗格顯示了格式化的文檔,反映了您在左側窗格中的代碼編輯器中執行的更改。代碼編輯器指出了所有格式錯誤。您可以展開和折疊每個窗格。
以下是您導入 leads.yaml 定義后的 Swagger Editor UI 外觀:
放在屏幕截圖上的紅色箭頭表示基於 OpenAPI 規范的 leads.yaml 文件中的 post:
和 get:
定義,與預覽文檔中 POST
和 GET
API 的文檔之間的對應關系。
如果使用 Eclipse 作為 IDE,您可以使用 YEdit,它會檢查並突出顯示 YAML 語法,還會提供編輯和格式化功能。
擴展 Swagger
現有的工具使編輯 Swagger API 文檔變得很容易,但某些文檔場景帶來了一些挑戰。以下這些是我們在使用 Swagger 記錄自己的 API 文檔時遇到的一些實際問題:
- API 使用者需要獲得特定於我們的 API 的信息,但 OpenAPI 規范不包含該信息的標准。
- API 使用者需要請求和響應示例,但現有的編輯器無法包含它們。
- 我們需要提供一個容易閱讀的富文檔,其中包含可供 API 使用者使用的示例,最好是采用在線 HTML 文檔形式。
為了解決這些問題,我們根據 OpenAPI 規范創建了自己的屬性、工具和模板。
擴展屬性
您可以使用 x-
擴展屬性來擴展 Swagger。以下是我們為自己的 API 專門定制的一些擴展,以及它們的用法示例:
以下屬性用於 API 有效負載或響應字段:
x-sc-crud
:記錄一個 API 字段的有效創建、讀取、更新和刪除(CRUD)操作:1x-sc-crud: [ read, update, create ]
x-sc-required
:指示此字段需要哪些 CRUD 操作:1x-sc-required: [ create ]
x-sc-fieldmap
:記錄與指定的 API 字段關聯的數據庫表和 UI 字段:123x-sc-fieldmap:
table: TASKS_RELATED_TO
uifieldname: Related to
x-sc-enum
:記錄 API 字段的有效值。可以不使用靜態值列表,而指定一個返回當前的可能值集合的 API。12x-sc-enum:
api: /leads/enum/alt_address_country
x-sc-comments
:為description
屬性提供補充,用於捕獲給定 API 字段的額外的臨時信息:12x-sc-comments:
- readonly in UI, aka Domestic Buying Group or DB
下面的清單是 Lead
模塊中的 lead_source
API 字段的 YAML 定義中的 x-sc
屬性的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
lead_source:
type: string
maxLength: 100
externalDocs:
description: Lead Source // Current (0100) // Approved // op - Opportunity
url: https://w3.ibm.com/standards/information/tmt/output/Approved/
ibmww/op/bds/Opportunity_Management/Lead_Source.html
#
# lead_source value is returned when retrieving a lead,
# and you can set its value when creating or updating a Lead.
#
x-sc-crud: [ read, update, create ]
#
# The lead_source is a required field when creating a Lead.
#
x-sc-required: [ create ]
#
# You can retrieve valid lead_source values from the
# /leads/enum/lead_source API.
#
x-sc-enum:
api: /leads/enum/lead_source
AVL:
dictionary_name: leads_lead_source_dom
example: LinkedIn
#
# The value of lead_source is saved in the LEADS table.
# In UI, you can find lead_source under the "Lead Source" label.
#
x-sc-fieldmap:
table: LEADS
uifieldname: Lead Source
|
以下屬性擴展了 API 操作的描述:
x-sc-samples
:記錄示例。此屬性包含對文檔的示例小節的 JSON 引用列表:(參見“包含示例”小節了解更多信息)123x-sc-samples:
- $ref: '#/x-sc-samples/leads-post-create-lead'
- $ref: '#/x-sc-samples/leads-post-create-lead-employeecnum'
x-sc-APIm-plans
:列出包含該操作的 IBM API Connect(以前稱為 IBM API Management)計划。我們希望捕獲特定於 API Manager 的信息:12x-sc-APIm-plans:
- salesconnect_leads_read
以下是 /leads
API 端點的 HTTP POST
方法的 YAML 資源中的 x-sc
屬性示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
paths:
/leads:
parameters:
- $ref: 'MASTER#/parameters/OAuthToken'
- $ref: 'MASTER#/parameters/ContentType'
post:
summary: create lead
tags: [ leads ]
#
# Use the x-sc-APIm-plans property to specify that this endpoint
# is in APIm's salesconnect_leads_create plan.
#
x-sc-APIm-plans:
- salesconnect_leads_create
description: |
<
p
>API to create a lead.</
p
>
#
# Use the x-sc-samples property to refer to samples of the usage
# of the /leads API.
#
x-sc-samples:
- $ref: '#/x-sc-samples/leads-post-create-lead'
- $ref: '#/x-sc-samples/leads-post-create-lead-employeecnum'
parameters:
- name: lead_definition
in: body
description: definition of lead to be created
schema:
$ref: '#/definitions/LeadObject'
responses:
200:
$ref: '#/responses/LeadObjectResponse'
422:
description: |
<
p
>scenarios</
p
>
<
ul
>
<
li
>missing required field</
li
>
<
li
>invalid values for optional fields</
li
>
<
li
>et cetera</
li
>
</
ul
>
|
包含示例
盡管 Swagger 是一個定義 RESTful API 的強大工具,但它未提供用於包含 HTTP 請求和響應示例,或者用於為開發人員添加已編寫文檔的途徑。
為了包含請求和響應示例,我們擴展了該規范,並再次使用了 YAML 來記錄示例。我們將自己的示例放在一個分離的模式(schema)中,這樣就不會讓主要 API 文檔過於復雜。
下面的 leads-post-create-lead
示例告訴使用者如何調用 /leads
API 的 HTTP POST
方法,描述 URL、方法、頭文件、URL 參數、輸入(示例有效負載)和響應:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
x-sc-samples:
leads-post-create-lead:
title: Create a New lead
description: |
This sample creates a new lead, and assigns it to a user specified via sugar user id.
method: POST
url: https://w3-dev.api.ibm.com/sales/development/salesconnect/leads
headers: |
Content-Type: application/json
Oauth-Token: 111e567a-7624-35f7-ed82-540f5a954312
Parameters: ?client_id={client_id}&client_secret={client_secret}
Input: |
{
"created_by": "eve25@tst.ibm.com",
"assigned_user_id": "51449f9b-a68f-059c-ad06-5039325c53b2",
"description": "2015-01-27 leads test",
"first_name": "one",
"last_name": "smith",
"phone_mobile": "22-222-2222",
...
}
Response: |
{
"my_favorite": false,
"following": false,
"id": "a260acfb-5b3e-3f74-2392-54d92387fb80",
"name": "one smith"
...
"_module": "Leads"
}
|
在 /leads
API 部分的 HTTP POST
方法中,我們使用了擴展的屬性 x-sc-samples
和對 x-sc-samples
模式中的示例代碼 leads-post-create-lead
的 JSON 引用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
paths:
/leads:
parameters:
- $ref: 'MASTER#/parameters/OAuthToken'
- $ref: 'MASTER#/parameters/ContentType'
post:
summary: create lead
tags: [ leads ]
x-sc-APIm-plans:
- salesconnect_leads_create
description: |
<
p
>API to create a lead.</
p
>
#
# Use the x-sc-samples property to refer to samples of the usage
# of the /leads API.
#
x-sc-samples:
- $ref: '#/x-sc-samples/leads-post-create-lead'
- $ref: '#/x-sc-samples/leads-post-create-lead-employeecnum'
parameters:
- name: lead_definition
in: body
description: definition of lead to be created
schema:
$ref: '#/definitions/LeadObject'
responses:
200:
$ref: '#/responses/LeadObjectResponse'
422:
description: |
<
p
>scenarios</
li
>
<
ul
>
<
li
>missing required field</
li
>
<
li
> invalid values for optional fields</
li
>
<
li
> et cetera</
li
>
</
ul
>
|
將定義和示例放在一起
為了將所有模塊定義和示例放在一起,我們使用了一個 MASTER.yaml 文件。此文件記錄了邏輯信息,包括 Swagger 版本、API 版本、總體信息和提供該 API 的相對基礎路徑(relative base path)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
swagger: '2.0'
info:
version: '3.4'
title: Sales Connect API
#
#
description: >
This is the SalesConnect API.
<
p
> There are several modules, each with different top level path.
Most of the modules follow the same general pattern for operations and results,
varying in the Sales Connect object that is manipulated.</
p
>
<
p
> The individual module descriptions show
the particular operations and any module specific details.</
p
>
#
#
basePath: /sales/test/salesconnect
host: w3-dev.api.ibm.com
|
此外,MASTER.yaml 還包含包、共享對象和模板的注解。
包
通過在 MASTER.yaml 文件中定義 package
(包)和 package sets
(包集)屬性,可以動態地生成內容。一個 package(包)定義了與給定模塊相關的所有 YAML 文件,而 package set(包集)是對最終文檔中的內容進行精細控制的包的集合。在我們的示例中, demo
和 default
包集分別從一組不同的文件中拉取內容。結合使用包和包集,我們可以輕松地將已發布模塊與仍在開發中的模塊分開。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
x-sc-master:
packages:
bulk:
- modules/bulk
#
# The oauth package contains 2 files:
# - the modules/oauth.yaml file
# - the samples/oauth-samples.yaml file
#
oauth:
- modules/oauth
- samples/oauth-samples
calls:
- modules/calls
- samples/calls-samples
collab:
- modules/collab
notes:
- modules/notes
- samples/notes-samples
...
leads:
- modules/leads
- samples/leads-samples
- samples/leadsTBD-samples
...
package-sets:
#
# When generating a "default" document, our tool pulls
# content from files specified under the "oauth", "bulk",
# "calls", "collab" and "notes" packages.
#
default:
- oauth
- bulk
- calls
- collab
- notes
#
# When generating a "demo" document, our tool pulls
# in a different set of files.
#
demo:
- oauth
- notes
- leads
|
共享對象
我們注意到,在實現過程中,反復提到了一些對象:多個 API 后端使用了相同的過濾器 URL 參數,多個 API 的 GET
方法返回了一組相同的基本字段,而且 API Manager 為不同的調用返回了相同的錯誤消息格式。為了減少冗余,我們使用 BasicObject
屬性和 APImException
對象將這些元素提取到 MASTER.yaml 文件中,前者定義了所有 HTTP 方法 GET
API 返回的基本字段,后者描述了從 API Manager 返回的錯誤結構。
使用模板
許多 API 的響應都遵循類似的模式,所以我們設計了模板來減少重復和支持變體。例如,當一個模塊鏈接到另一個模塊時,一些 API 的響應將包含來自二者的對象。為了適應這種情形,我們在 MASTER.yaml 文件中設計了一個 (OBJECT)Link(otherOBJECT)Response
模板:
1
2
3
4
5
6
7
8
9
10
11
|
(OBJECT)Link(otherOBJECT)Response:
description: |
Result of creating link from (OBJECT) to (otherOBJECT).
The record contains the (OBJECT) and the <
em
>related_record</
em
> the (otherOBJECT) objects.
schema:
properties:
record:
$ref: 'MASTER#/definitions/(OBJECT)'
related_record:
$ref: 'MASTER#/definitions/(otherOBJECT)'
|
當記錄一個將 Note
模塊 (OBJECT=NoteObject)
鏈接到 Account
模塊 (otherOBJECT=AccountObject)
的 API 的響應時,可以采用以下格式:
1
2
3
4
5
6
7
|
post:
summary: Establish an accounts link to note using ccms id.
description: Establish an accounts link to note using ccms id.
responses:
default:
$ref: 'MASTER?OBJECT=NoteObject&otherOBJECT=AccountObject#/responses/
(OBJECT)Link(otherOBJECT)Response'
|
在我們的示例中,$ref
告訴該工具訪問 MASTER.yaml 文件並在 responses
模式下查找(OBJECT)Link(otherOBJECT)Response
對象。實例化 JSON 引用之前,該工具將 OBJECT
變量替換為 NoteObject
,將 otherOBJECT
替換為 AccountObject
。最終,該模板被擴展為:
1
2
3
4
5
6
7
8
9
10
11
|
NoteObjectLinkAccountObjectResponse:
description: |
Result of creating link from NoteObject to AccountObject.
The record contains the NoteObject and the <
em
>related_record</
em
> the AccountObject objects.
schema:
properties:
record:
$ref: 'MASTER#/definitions/NoteObject'
related_record:
$ref: 'MASTER#/definitions/AccountObject'
|
類似地,您可以通過將 OBJECT
和 otherOBJECT
設置為不同的值,使用此模板來記錄將 Note
模塊鏈接到 Opportunity
模塊的 API 的響應:
1
2
3
4
5
6
7
8
9
|
post:
summary: Link from note to opportunity.
description: Link from note to opportunity.
x-sc-APIm-plans: [ salesconnect_notes_create ]
responses:
default:
$ref:
'MASTER?OBJECT=NoteObject&otherOBJECT=OpportunityObject#/responses/
(OBJECT)Link(otherOBJECT)Response'
|
將 YAML 文檔轉換為 HTML 頁面
為了讓 API 文檔對用戶更友好,我們實現了一個工具(swagger-to-html.php)來將 YAML 文檔轉換為靜態 HTML。盡管可以使用現有工具從 Swagger 構建 HTML 文檔,但我們決定創建自己的工具,以便可以添加對 x-sc-*
擴展的特殊處理功能。
該工具將會讀入 MASTER.yaml 文件,合並所有必要的 YAML 文件,解析引用,然后輸出一個 HTML 頁面。該工具接受許多不同的參數,您可使用它們來自定義 HTML 文件的內容。例如,您可以為特定模塊生成 HTML 文件,為特定包集生成 HTML 文件,或者僅為向 IBM API Management 應用程序注冊的 API 生成 HTML 文件。
生成的 HTML 是單個文件,它使用 CSS 設置樣式,使用 JavaScript 自動化各個部分的折疊、展開和導航功能。HTML 生成器工具會呈現通用 JSON 對象、JSON 模式定義,以及參數、響應、操作等的 Swagger 描述。
這是為 Lead
模塊中的 lead_source
項生成的 HTML 頁面(請參閱“擴展屬性”部分的相應 YAML 文檔):
這是來自 /leads
API 端點的 HTTP POST
方法的 HTML 頁面(請參閱“包含示例”部分的相應 YAML 文檔):
幕后原理
這個 API-swagger.zip 文件(參見“下載”)演示了我們的 Swagger API 文檔子集中針對 SalesConnect
系統中的三個模塊的部分:OAuth
、Lead
和 Note
。這些 API 位於 /modules 目錄中,相應的示例包含在 /samples 目錄中。
要生成 HTML 頁面:
- 安裝必備軟件(PHP 和 PHP YAML 擴展)。
- 使用
cd
命令轉到 API-Swagger 目錄。 - 要為 MASTER.yaml 文件的演示包集中指定的所有 API 生成 HTML,請輸入以下命令(將它輸入在一行上):
php tools/swagger-to-html.php
salesconnect.swagger/
MASTER.yaml --set demo >
c:/swagger/salesconnectAPI.html
- 要為模塊
OAuth
和Lead
生成 HTML,請輸入以下命令(將它輸入在一行上):php tools/swagger-to-html.php salesconnect.swagger/MASTER.yaml --modules oauth,leads > c:/swagger/salesconnectAPI.html
結束語
Swagger 是一個為 RESTful API 創建文檔的強大工具,而且通過實現自定義擴展、工具和模板,您可以獲得對 Swagger 生成的文檔的格式和內容的更多選擇和控制。通過擴展 Swagger 的功能,您可以包含更多特定於 API 的細節,指定 HTTP 請求和響應,並以 HTML 格式輸出文檔,以便開發人員和 API 使用者都可以閱讀。
下載資源
- 示例代碼 (API-swagger.zip | 83KB)
http://www.ibm.com/developerworks/cn/web/wa-use-swagger-to-document-and-define-restful-apis/index.html