使用 $ref
当你记录 API 时,通常会有一些你跨多个 API 资源使用的功能。在这种情况下,你可以为这些元素创建一个片段,以便在需要时多次使用它们。使用 OpenAPI 3.0,你可以引用托管在任何位置的定义。它可以是同一台服务器,也可以是另一台服务器——例如,GitHub、SwaggerHub 等。要引用定义,请使用 $ref
关键字
1$ref: "reference to definition"
例如,假设你有以下模式对象,你想在你的响应中使用它
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 指针中的特殊字符,需要在字面使用时进行转义(例如,在路径名称中)。
字符 | 使用以下内容转义 |
---|---|
~ | ~0 |
/ | ~1 |
例如,要引用路径 /blogs/{blog_id}/new~posts
,你将使用
1$ref: "#/paths/~1blogs~1{blog_id}~1new~0posts"
注意事项
可以 使用 $ref 的位置
一个常见的误解是 $ref
允许在 OpenAPI 规范文件中的任何位置使用。实际上,$ref
仅允许在 OpenAPI 3.0 规范 明确声明该值可能是引用的位置。例如,不能在 info
部分和 paths
下直接使用 $ref
1openapi: 3.0.02
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
在第二个模式中,description
和 default
属性将被忽略,因此此模式最终与引用的 Date
模式完全相同。