Skip to content

Links

Links are one of the new features of OpenAPI 3.0. Using links, you can describe how various values returned by one operation can be used as input for other operations. This way, links provide a known relationship and traversal mechanism between the operations. The concept of links is somewhat similar to hypermedia, but OpenAPI links do not require the link information present in the actual responses.

Consider the “create user” operation:

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
}

This user ID can then be used to read, update or delete the user: GET /users/305, PATCH /users/305 and DELETE /users/305. Using links, you can specify that the id value returned by “create user” can be used as a parameter to “get user”, “update user” and “delete user”. Another example is pagination via cursors, where the response includes a cursor to retrieve the next data set:

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

However, linking relationships are not necessarily within the same resource, or even the same API specification.

Links are defined in the links section of each response:

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

To better understand this, let’s look at a complete example. This API defines the “create user” and “get user” operations, and the result of “create user” is used as an input to “get user”.

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

The links section contains named link definitions, in this example – just one link named GetUserByUserId. The link names can only contain the following characters:

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

Each link contains the following information:

  • operationId or operationRef that specifies the target operation. It can be the same operation or a different operation in the current or external API specification. operationId is used for local links only, and operationRef can link to both local and external operations.
  • parameters and/or requestBody sections that specify the values to pass to the target operation. Runtime expression syntax is used to extract these values from the parent operation.
  • (Optional) The server that the target operation should use, if it is different from the default servers.
  • (Optional) A description of this link. CommonMark syntax can be used for rich text representation.

The rest of this page goes into more detail about these keywords.

OpenAPI 3.0 links

operationId

If the target operation has operationId specified, the link can point to this ID – as in the image above. This approach can be used for local links only, because the operationId values are resolved in the scope of the current API specification.

operationRef

operationRef can be used when operationId is not available. operationRef is a reference to the target operation using the JSON Reference syntax – same as used by the $ref keyword. References can be local (within the current API specification):

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

or external:

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

Here, the string #/paths/~1users~1{userId}/get actually means #/paths//users/{userId}/get, but the inner slashes / in the path name need to be escaped as ~1 because they are special characters.

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

This syntax can be difficult to read, so we recommend using it for external links only. In case of local links, it is easier to assign operationId to all operations and link to these IDs instead.

parameters and requestBody

The most important part of a link is computing the input for the target operation based on the values from the original operation. This is what the parameters and requestBody keywords are for.

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"

The syntax is _parameter_name: value_ or requestBody: value. The parameter names and request body are those of the target operation. There is no need to list all the parameters, just those required to follow the link. Similarly, requestBody is only used if the target operation has a body and the link purpose is to define the body contents. If two or more parameters have the same name, prefix the names with the parameter location – path, query, header or cookie, like so:

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

The values for parameters and requestBody can be defined in the following ways:

  • runtime expressions, such as $response.body#/id, that refer to the values in the request or response of the original operation,
  • strings containing embedded runtime expressions, such as ID_{$response.body#/id},
  • hard-coded values – strings, numbers, arrays, and so on, such as mystring or true.

You would typically use constant values if you need to pass a specific combination of evaluated and hard-coded parameters for the target operation.

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
...

Runtime Expression Syntax

OpenAPI runtime expressions are syntax for extracting various values from an operation’s request and response. Links use runtime expressions to specify the parameter values to be passed to the linked operation. The expressions are called “runtime” because the values are extracted from the actual request and response of the API call and not, say, the example values provided in the API specification. The following table describes the runtime expression syntax. All expressions refer to the current operation where the links are defined.

Expression

Description

$url

The full request URL, including the query string.

$method

Request HTTP method, such as GET or POST.

$request.query._param_name_

The value of the specified query parameter. The parameter must be defined in the operation’s parameters section, otherwise, it cannot be evaluated. Parameter names are case-sensitive.

$request.path._param_name_

The value of the specified path parameter. The parameter must be defined in the operation’s parameters section, otherwise, it cannot be evaluated. Parameter names are case-sensitive.

$request.header._header_name_

The value of the specified request header. This header must be defined in the operation’s parameters section, otherwise, it cannot be evaluated. Header names are case-insensitive.

$request.body

The entire request body.

$request.body_#/foo/bar_

A portion of the request body specified by a JSON Pointer.

$statusCode

HTTP status code of the response. For example, 200 or 404.

$response.header._header_name_

The complete value of the specified response header, as a string. Header names are case-insensitive. The header does not need to be defined in the response’s headers section.

$response.body

The entire response body.

$response.body_#/foo/bar_

A portion of the request body specified by a JSON Pointer.

foo{$request.path.id}bar

Enclose an expression into {} curly braces to embed it into a string.

Notes:

  • The evaluated expression has the same type as the referenced value, unless noted otherwise.
  • If a runtime expression cannot be evaluated, no parameter value is passed to the target operation.

Examples

Consider the following request and response:

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
}

Below are some examples of runtime expressions and the values they evaluate to:

ExpressionResultComments
$urlhttp://api.example.com/users?limit=2&total=true
$methodGET
$request.query.totaltruetotal must be defined as a query parameter.
$statusCode200
$response.header.x-total-count37Assuming X-Total-Count is defined as a response header. Header names are case-insensitive.
$response.body#/next_offset2
$response.body#/users/0{"id": 1, "name": "Alice"}JSON Pointer (the #/... part) uses 0-based indexes to access array elements. There is no wildcard syntax though, so $response.body#/users/*/id is not valid.
$response.body#/users/1{"id": 2, "name": "Bob"}
$response.body#/users/1/nameBob
ID_{$response.body#/users/1/id}ID_2

server

By default, the target operation is called against its default servers – either global servers, or operation-specific servers. However, the server can be overridden by the link using the server keyword. server has the same fields as global servers, but it is a single server and not an array.

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

Links can be defined inline (as in the previous examples), or placed in the global components/links section and referenced from an operation’s links section via $ref. This can be useful if multiple operations link to another operation in the same way – referencing helps reduce code duplication. In the following example, both the “create user” and “update user” operations return the user ID in the response body, and this ID is used in the “get user” operation. The source operations reuse the same link definition from 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'

References

Link Object

Did not find what you were looking for? Ask the community
Found a mistake? Let us know