使用 $ref
在文档化 API 时,通常会有一些您在多个 API 资源中使用的功能。在这种情况下,您可以为这些元素创建代码片段,以便在需要时多次使用它们。借助 OpenAPI 3.0,您可以引用托管在任何位置的定义。它可以是同一服务器,也可以是另一个服务器——例如,GitHub、SwaggerHub 等。要引用定义,请使用 $ref
关键字
1$ref: "reference to definition"
例如,假设您有以下 schema 对象,您希望在响应中使用它
1"components":2 {3 "schemas":4 {5 "user":6 {7 "properties":8 { "id": { "type": "integer" }, "name": { "type": "string" } },9 },10 },11 }
1components:2 schemas:3 User:4 properties:5 id:6 type: integer7 name:8 type: string
要引用该对象,您需要在响应中添加 $ref
以及相应的路径
1"responses":2 {3 "200":4 {5 "description": "The response",6 "schema": { "$ref": "#/components/schemas/user" },7 },8 }
1responses:2 "200":3 description: The response4 schema:5 $ref: "#/components/schemas/User"
$ref
的值使用 JSON Reference 符号,而以 #
开头的部分则使用 JSON Pointer 符号。这种符号允许您指定要引用的目标文件或文件的特定部分。在前面的示例中,#/components/schemas/User
表示解析从当前文档的根目录开始,然后依次查找 components
、schemas
和 User
的值。
$ref 语法
根据 RFC3986,$ref
字符串值 (JSON Reference) 应该包含一个 URI,该 URI 标识您正在引用的 JSON 值的位置。如果字符串值不符合 URI 语法规则,则在解析期间会导致错误。JSON Reference 对象中除 $ref
之外的任何成员都将被忽略。请查看此列表以了解特定情况下 JSON 引用的示例值
- 本地引用 –
$ref: '#/definitions/myElement'
#
表示转到当前文档的根目录,然后依次查找元素definitions
和myElement
。 - 远程引用 –
$ref: 'document.json'
使用位于同一服务器和同一位置的整个文档。- 位于同一文件夹中的文档元素 –
$ref: 'document.json#/myElement'
- 位于父文件夹中的文档元素 –
$ref: '../document.json#/myElement'
- 位于另一个文件夹中的文档元素 –
$ref: '../another-folder/document.json#/myElement'
- 位于同一文件夹中的文档元素 –
- URL 引用 –
$ref: 'http://path/to/your/resource'
使用位于不同服务器上的整个文档。- 存储在不同服务器上的文档特定元素 –
$ref: 'http://path/to/your/resource.json#/myElement'
- 位于不同服务器上、使用相同协议(例如 HTTP 或 HTTPS)的文档 –
$ref: '//anotherserver.com/files/example.json'
- 存储在不同服务器上的文档特定元素 –
注意:在 YAML 中使用 #/components/schemas/User
等本地引用时,请将值用引号括起来:'#/components/schemas/User'
。否则它将被视为注释。
转义字符
/
和 ~
是 JSON Pointer 中的特殊字符,在字面使用时(例如在路径名中)需要进行转义。
字符 | 转义为 |
---|---|
~ | ~0 |
/ | ~1 |
例如,要引用路径 /blogs/{blog_id}/new~posts
,您将使用
1$ref: "#/paths/~1blogs~1{blog_id}~1new~0posts"
注意事项
$ref 可用位置
一个常见的误解是 $ref
可以在 OpenAPI 规范文件的任何地方使用。实际上,$ref
仅允许在 OpenAPI 3.0 规范明确指出该值可以是 *引用* 的位置使用。例如,$ref
不能用于 info
部分和 paths
下方。
1openapi: 3.0.42
3# Incorrect!4info:5 $ref: info.yaml6paths:7 $ref: paths.yaml
但是,您可以 $ref
单个路径,如下所示
1paths:2 /users:3 $ref: "../resources/users.yaml"4 /users/{userId}:5 $ref: "../resources/users-by-id.yaml"
$ref 和同级元素
$ref
的任何同级元素都将被忽略。这是因为 $ref
的工作原理是用它所指向的定义替换自身及其所有同级内容。考虑以下示例
1components:2 schemas:3 Date:4 type: string5 format: date6
7 DateWithExample:8 $ref: "#/components/schemas/Date"9 description: Date schema extended with a `default` value... Or not?10 default: 2000-01-01
在第二个 schema 中,description
和 default
属性被忽略,因此此 schema 最终与引用的 Date
schema 完全相同。