跳至內容

連結

連結是 OpenAPI 3.0 的新功能之一。使用連結,您可以描述一個操作傳回的各種值如何用作其他操作的輸入。這樣,連結會在操作之間提供已知的關係和遍歷機制。連結的概念有點類似於 超媒體,但 OpenAPI 連結不需要在實際回應中存在連結資訊。

考慮「建立使用者」操作

1
POST /users HTTP/1.1
2
Host: example.com
3
Content-Type: application/json
4
5
{
6
"name": "Alex",
7
"age": 27
8
}
9
10
which returns the ID of the created user:
11
12
HTTP/1.1 201 Created
13
Content-Type: application/json
14
15
{
16
"id": 305
17
}

然後可以使用此使用者 ID 來讀取、更新或刪除使用者:GET /users/305PATCH /users/305DELETE /users/305。使用連結,您可以指定「建立使用者」傳回的 id 值可以用作「取得使用者」、「更新使用者」和「刪除使用者」的參數。另一個範例是透過游標進行分頁,其中回應包含用於擷取下一個資料集的游標

1
GET /items?limit=100
2
3
4
5
{
6
"metadata": {
7
"previous": null,
8
"next": "Q1MjAwNz",
9
"count": 10
10
},
11
...
12
}
13
14
15
16
GET /items?cursor=Q1MjAwNz&limit=100

然而,連結關係不一定在相同的資源內,甚至不在相同的 API 規格內。

連結在每個回應的 links 區段中定義

1
responses:
2
"200":
3
description: Created
4
content: ...
5
links: # <----
6
...
7
"400":
8
description: Bad request
9
content: ...
10
links: # <----
11
...

為了更好地理解這一點,讓我們來看一個完整的範例。此 API 定義了「建立使用者」和「取得使用者」操作,「建立使用者」的結果用作「取得使用者」的輸入。

1
openapi: 3.0.0
2
info:
3
version: 0.0.0
4
title: Links example
5
6
paths:
7
/users:
8
post:
9
summary: Creates a user and returns the user ID
10
operationId: createUser
11
requestBody:
12
required: true
13
description: A JSON object that contains the user name and age.
14
content:
15
application/json:
16
schema:
17
$ref: "#/components/schemas/User"
18
responses:
19
"201":
20
description: Created
21
content:
22
application/json:
23
schema:
24
type: object
25
properties:
26
id:
27
type: integer
28
format: int64
29
description: ID of the created user.
30
# -----------------------------------------------------
31
# Links
32
# -----------------------------------------------------
33
links:
34
GetUserByUserId: # <---- arbitrary name for the link
35
operationId: getUser
36
# or
37
# operationRef: '#/paths/~1users~1{userId}/get'
38
parameters:
39
userId: "$response.body#/id"
40
41
description: >
42
The `id` value returned in the response can be used as
43
the `userId` parameter in `GET /users/{userId}`.
44
# -----------------------------------------------------
45
46
/users/{userId}:
47
get:
48
summary: Gets a user by ID
49
operationId: getUser
50
parameters:
51
- in: path
52
name: userId
53
required: true
54
schema:
55
type: integer
56
format: int64
57
responses:
58
"200":
59
description: A User object
60
content:
61
application/json:
62
schema:
63
$ref: "#/components/schemas/User"
64
65
components:
66
schemas:
67
User:
68
type: object
69
properties:
70
id:
71
type: integer
72
format: int64
73
readOnly: true
74
name:
75
type: string

links 區段包含具名的連結定義,在此範例中,只有一個名為 GetUserByUserId 的連結。連結名稱只能包含下列字元

1
A..Z a..z 0..9 . _ -

每個連結都包含下列資訊

  • operationIdoperationRef,指定目標操作。它可以是相同操作或目前或外部 API 規格中的不同操作。operationId 僅用於本機連結,而 operationRef 可以連結到本機和外部操作。
  • parameters 和/或 requestBody 區段,指定要傳遞給目標操作的值。使用 執行階段運算式 語法,從父操作中擷取這些值。
  • (選用) 目標操作應使用的 server,如果它與預設伺服器不同。
  • (選用) 此連結的 descriptionCommonMark 語法可用於豐富文字表示。

此頁面的其餘部分將更詳細地介紹這些關鍵字。

OpenAPI 3.0 links

operationId

如果目標操作已指定 operationId,則連結可以指向此 ID,如上圖所示。此方法僅適用於本機連結,因為 operationId 值會在目前 API 規格的範圍內解析。

operationRef

operationId 不可用時,可以使用 operationRefoperationRef 是使用 JSON 參考語法參考目標操作,與 $ref 關鍵字使用的語法相同。參考可以是本機 (在目前 API 規格內)

1
operationRef: "#/paths/~1users~1{userId}/get"

或外部

1
operationRef: 'https://anotherapi.com/openapi.yaml#/paths/~1users~1{userId}/get'
2
operationRef: './operations/getUser.yaml'

在此,字串 #/paths/~1users~1{userId}/get 實際上表示 #/paths//users/{userId}/get,但路徑名稱中的內部斜線 / 需要逸出為 ~1,因為它們是特殊字元。

1
#/paths/~1users~1{userId}/get
2
│ │ │
3
│ │ │
4
paths: │ │
5
/users/{userId}:
6
get: ─────────────────┘
7
...

此語法可能難以閱讀,因此我們建議僅將其用於外部連結。對於本機連結,將 operationId 指派給所有操作並連結到這些 ID 會更容易。

parameters 和 requestBody

連結最重要的部分是根據原始操作的值計算目標操作的輸入。這就是 parametersrequestBody 關鍵字的作用。

1
links:
2
# GET /users/{userId}
3
GetUserByUserId:
4
operationId: getUser
5
parameters:
6
userId: "$response.body#/id"
7
8
# POST /users/{userId}/manager with the manager ID in the request body
9
SetManagerId:
10
operationId: setUserManager
11
requestBody: "$response.body#/id"

語法為 _parameter_name: value_requestBody: value。參數名稱和請求主體是目標操作的名稱。無需列出所有參數,只需列出遵循連結所需的參數即可。同樣地,只有在目標操作有 主體 且連結的目的是定義主體內容時,才使用 requestBody。如果兩個或更多參數具有相同的名稱,請使用參數位置 (pathqueryheadercookie) 做為名稱的前置詞,如下所示

1
parameters:
2
path.id: ...
3
query.id: ...

參數和 requestBody 的值可以使用以下方式定義

  • 執行階段運算式,例如 $response.body#/id,它會參考原始操作的請求或回應中的值,
  • 包含內嵌執行階段運算式的字串,例如 ID_{$response.body#/id}
  • 硬式編碼的值 (字串、數字、陣列等等),例如 mystringtrue

如果您需要為目標操作傳遞已評估和硬式編碼參數的特定組合,您通常會使用常數值。

1
paths:
2
/date_ranges:
3
get:
4
summary: Get relative date ranges for the report.
5
responses:
6
'200':
7
description: OK
8
content:
9
application/json:
10
example: [Today, Yesterday, LastWeek, ThisMonth]
11
links:
12
ReportRelDate:
13
operationId: getReport
14
# Call "getReport" with the `rdate` parameter and with empty `start_date` and `end_date`
15
parameters:
16
rdate: '$response.body#/1'
17
start_date: ''
18
end_date: ''
19
20
# GET /report?rdate=...
21
# GET /report?start_date=...&end_date=...
22
/report:
23
get:
24
operationId: getReport
25
...

執行階段運算式語法

OpenAPI 執行階段運算式是從操作的請求和回應中擷取各種值的語法。連結使用執行階段運算式來指定要傳遞給連結操作的參數值。這些運算式稱為「執行階段」,因為這些值是從 API 呼叫的實際請求和回應中擷取的,而不是從 API 規格中提供的 範例值 中擷取的。下表描述了執行階段運算式語法。所有運算式都參考定義 links目前操作

運算式

描述

$url

完整的請求 URL,包括查詢字串。

$method

請求 HTTP 方法,例如 GET 或 POST。

$request.query._param_name_

指定查詢參數的值。該參數必須在操作的 parameters 區段中定義,否則無法評估。參數名稱區分大小寫。

$request.path._param_name_

指定路徑參數的值。該參數必須在操作的 parameters 區段中定義,否則無法評估。參數名稱區分大小寫。

$request.header._header_name_

指定請求標頭的值。此標頭必須在操作的 parameters 區段中定義,否則無法評估。標頭名稱不區分大小寫。

$request.body

整個請求主體。

$request.body_#/foo/bar_

請求主體中由 JSON 指標指定的部分。

$statusCode

回應的 HTTP 狀態碼。例如,200 或 404。

$response.header._header_name_

指定的回應標頭的完整值,以字串形式表示。標頭名稱不區分大小寫。該標頭不需要在回應的 headers 區段中定義。

$response.body

整個回應主體。

$response.body_#/foo/bar_

請求主體中由 JSON 指標指定的部分。

foo{$request.path.id}bar

將運算式放入 {} 大括號中,以便將其嵌入到字串中。

注意事項

  • 評估後的運算式具有與參考值相同的類型,除非另有說明。
  • 如果無法評估執行階段運算式,則不會將任何參數值傳遞給目標操作。

範例

考慮以下請求和回應

1
GET /users?limit=2&total=true
2
Host: api.example.com
3
Accept: application/json
1
HTTP/1.1 200 OK
2
Content-Type: application/json
3
X-Total-Count: 37
4
5
{
6
"prev_offset": 0,
7
"next_offset": 2,
8
"users": [
9
{"id": 1, "name": "Alice"},
10
{"id": 2, "name": "Bob"}
11
]
12
}

以下是一些執行階段運算式的範例以及它們評估後的值

運算式結果註解
$urlhttp://api.example.com/users?limit=2&total=true
$methodGET
$request.query.totaltruetotal 必須定義為查詢參數。
$statusCode200
$response.header.x-total-count37假設 X-Total-Count 定義為回應標頭。標頭名稱不區分大小寫。
$response.body#/next_offset2
$response.body#/users/0{"id": 1, "name": "Alice"}JSON 指標(#/... 部分)使用以 0 為基礎的索引來存取陣列元素。但是沒有萬用字元語法,因此 $response.body#/users/*/id 無效。
$response.body#/users/1{"id": 2, "name": "Bob"}
$response.body#/users/1/nameBob
ID_{$response.body#/users/1/id}ID_2

伺服器

預設情況下,目標操作會針對其預設的 伺服器 呼叫 – 全域 servers 或操作特定的 servers。但是,可以使用 server 關鍵字覆寫連結的伺服器。server 具有與全域伺服器相同的欄位,但它是一個單一伺服器,而不是陣列。

1
servers:
2
- url: https://api.example.com
3
---
4
links:
5
GetUserByUserId:
6
operationId: getUser
7
parameters:
8
userId: "$response.body#/id"
9
server:
10
url: https://new-api.example.com/v2

連結可以內嵌定義(如先前的範例所示),或放置在全域 components/links 區段中,並透過 $ref 從操作的 links 區段中參考。如果多個操作以相同的方式連結到另一個操作,這可能會很有用 – 參考有助於減少程式碼重複。在以下範例中,「建立使用者」和「更新使用者」操作都會在回應主體中傳回使用者 ID,此 ID 用於「取得使用者」操作。來源操作會重複使用 components/links 中的相同連結定義。

1
paths:
2
/users:
3
post:
4
summary: Create a user
5
operationId: createUser
6
...
7
responses:
8
'201':
9
description: Created
10
content:
11
application/json:
12
schema:
13
type: object
14
properties:
15
id:
16
type: integer
17
format: int64
18
description: ID of the created user.
19
links:
20
GetUserByUserId:
21
$ref: '#/components/links/GetUserByUserId' # <-------
22
23
/user/{userId}:
24
patch:
25
summary: Update user
26
operationId: updateUser
27
...
28
responses:
29
'200':
30
description: The updated user object
31
content:
32
application/json:
33
schema:
34
$ref: '#/components/schemas/User'
35
links:
36
GetUserByUserId:
37
$ref: '#/components/links/GetUserByUserId' # <-------
38
39
get:
40
summary: Get a user by ID
41
operationId: getUser
42
...
43
44
components:
45
links:
46
GetUserByUserId: # <----- The $ref's above point here
47
description: >
48
The `id` value returned in the response can be used as
49
the `userId` parameter in `GET /users/{userId}`.
50
operationId: getUser
51
parameters:
52
userId: '$response.body#/id'

參考

連結物件

找不到您要找的東西嗎? 向社群提問
發現錯誤? 讓我們知道