跳到内容

链接

链接是 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
  • (可选)此链接的 description。可以使用 CommonMark 语法进行富文本表示。

本页的其余部分将详细介绍这些关键字。

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

server

默认情况下,目标操作针对其默认服务器调用,即全局 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'

引用

链接对象

没有找到您要找的内容?请咨询社区
发现错误? 请告知我们