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.
When to Use Links?
Consider the “create user” operation:
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:
However, linking relationships are not necessarily within the same resource, or even the same API specification.
Defining Links
Links are defined in the links
section of each response:
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”.
The links
section contains named link definitions, in this example – just one link named GetUserByUserId. The link names can only contain the following characters:
Each link contains the following information:
operationId
oroperationRef
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, andoperationRef
can link to both local and external operations.parameters
and/orrequestBody
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.
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):
or external:
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.
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.
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:
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
ortrue
.
You would typically use constant values if you need to pass a specific combination of evaluated and hard-coded parameters for the target operation.
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:
Below are some examples of runtime expressions and the values they evaluate to:
Expression | Result | Comments |
---|---|---|
$url | http://api.example.com/users?limit=2&total=true | |
$method | GET | |
$request.query.total | true | total must be defined as a query parameter. |
$statusCode | 200 | |
$response.header.x-total-count | 37 | Assuming X-Total-Count is defined as a response header. Header names are case-insensitive. |
$response.body#/next_offset | 2 | |
$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/name | Bob | |
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.
Reusing Links
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
.
References
Did not find what you were looking for? Ask the community
Found a mistake? Let us know