diff --git a/versions/3.0.md b/versions/3.0.md index 2bfca451ce..96c7814515 100644 --- a/versions/3.0.md +++ b/versions/3.0.md @@ -938,7 +938,7 @@ default: ``` #### Response Object -Describes a single response from an API Operation. +Describes a single response from an API Operation, including design-time, static `links` to operations based on the response. ##### Fixed Fields Field Name | Type | Description @@ -947,6 +947,8 @@ Field Name | Type | Description schema | [Schema Object](#schemaObject) | A definition of the response structure. It can be a primitive, an array or an object. If this field does not exist, it means no content is returned as part of the response. As an extension to the [Schema Object](#schemaObject), its root `type` value may also be `"file"`. This SHOULD be accompanied by a relevant `produces` media type. headers | [Headers Object](#headersObject) | A list of headers that are sent with the response. examples | [Example Object](#exampleObject) | An example of the response message. +links | [Links Object](#linksObject) | An object representing operations related to the response payload. + ##### Patterned Objects @@ -1123,6 +1125,397 @@ application/json: breed: Mixed ``` +#### Links Object +The links object represents a set of possible design-time links for a response. The presence of a link does not guarantee the caller's ability to successfully call invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations. + +As opposed to _dynamic_ links--that is, links provided **in** the response payload, the OAS linking mechanism does not require that link information be provided in a specific response format at runtime. + +For computing links, and providing instructions to execute them, a mechanism is defined for accessing values in a response and using them as variables while invoking the linked operation. + +Field Name | Type | Description +---|:---:|--- +$ref | `string` | If present, a reference to another Links Object. Note, the presence of `$ref` in the Links Object will cause all _Patterned Objects_ to be ignored. + +Field Pattern | Type | Description +---|:---:|--- +link name | [Link Object](#linkObject) | A short name for the link, following the naming constraints of the definitions name. The link shall reference a single Link Object, or a JSON Reference to a single link object + + +### Link Object +The `Link Object` is responsible for defining a possible operation based on a single response. + +Field Name | Type | Description +---|:---:|--- +href | url | a relative or absolute URL to a linked resource. This field is mutually exclusive with the `operationId` field. +operationId | string | the name of an _existing_, resolvable OAS operation, as defined with a unique `operationId`. This field is mutually exclusive with the `href` field. Relative `href` values _may_ be used to locate an existing Operation Object in the OAS. +parameters | Link Parameters Object | an Object representing parameters to pass to an operation as specified with `operationId` or identified via `href`. +headers | Link Headers Object | an Object representing headers to pass to the linked resource. +description | string | a description of the link, supports GFM. +^x- | Any | Allows extensions to the OpenAPI Schema. The field name MUST begin with `x-`, for example, `x-internal-id`. The value can be `null`, a primitive, an array or an object. See [Specification Extensions](#specificationExtensions) for further details. + +Locating a linked resource may be performed by either a `href` or `operationId`. In the case of an `operationId`, it must be unique and resolved in the scope of the OAS document. Because of the potential for name clashes, consider the `href` syntax as the preferred method for specifications with external references. + +#### Response Payload Values + +Payload values are only available in parseable response payloads which match the advertised media-type. In all cases, if a value does _not_ exist, the parameter will be considered a `null` value (as opposed to an empty value) and _not_ passed as a parameter to the linked resource. In cases where a value is required, and a parameter is not supplied, the client _may_ choose to not follow the link definition. + +### Example + +Response payload: +```json +{ + "id": "df71a505-07bc-458a-a5c0-73c0340d1ec7", + "firstname": "Ash", + "lastname": "Williams" +} +``` + +Payload Variables: +```yaml +id: df71a505-07bc-458a-a5c0-73c0340d1ec7 +firstname: Ash +lastname: Williams +missingValue: null +``` + +In situations where variables appear in an array, an array of variables will be extracted. For example: + +```json +[ + { "color": "red" }, + { "color": "green" }, + { "color": "blue" } +] +``` + +will be extracted as such: + +```json +color: ["red", "green", "blue"] +``` + +The variables generated can be used in locations prescribed by the definition. + + +### Variable substitution +In all cases, _variables_ from request and responses may be substituted for link generation. The table below designates the source of the substitution value and the syntax for accessing it: + +Source Location | reference identifier | example value | example reference | notes +---|:---|:---|:--- +HTTP Method | `$method` | `/users/{$method}` | The allowable values for the `$method` will be those for the HTTP operation +Requested content type | `$accepts` | `/users/3?format={$accepts}` | +Request parameter | `$request` | `/users/{$request.id}` | Request parameters must be declared in the `parameters` section for the operation or they cannot be used in substitution. This includes request headers +Request body | `$requestBody` | `/users/{$requestBody.user.uuid}` | For operations which accept payloads, references may be made to portions of the `requestBody` or the entire body itself +Request URL | `$url` | `/track?url={$url}` | +Response value | `$response` | `{$response.uuid}` | Only the payload in the response can be accessed with the `$response` syntax +Response header | `$responseHeader` | `{$responseHeader.Server}` | Single header values only are available. + +From the request, the `parameter`s used in calling the operation are made available through the `$request` syntax. For responses, the response payload may be used with the `$response` syntax. For both requests and responses, values will be substituted in the link in sections designated with the `$request` or `$response` keyword, surrounded by curly brackets `{}`. + +### Request parameter example +Computing a link from a request operation like such: + +```yaml +paths: + /users/{id}: + parameters: + - name: id + in: path + required: true + description: the user identifier, as userId or username + schema: + type: string + responses: + 200: + description: the user being returned + schema: + type: object + properties: + uuid: the unique user id + type: string + format: uuid +``` + +Can be used in a link like this: + +```yaml +Addresses: + href: '/users/{$request.id}/department' +``` + +Where the `$request.id` is the value passed in the request to `/users/{id}`. For a `id` value of `10101110`, the generated link would be: + +```yaml +href: '/users/10101110/department' +``` + +### Response payload example + +```yaml +Addresses: + href: '/users/{$response.uuid}/address' +``` + +Where the `$response.uuid` from the example above would yield the target: + + +```yaml +href: '/users/df71a505-07bc-458a-a5c0-73c0340d1ec7/address' +``` + +And the array example: + +```yaml +ColorSelection: + href: 'http://colors.my-server.com/colors/{$response.color}' +``` + +Would produce the following links: + +```yaml +href: 'http://colors.my-server.com/colors/red' +href: 'http://colors.my-server.com/colors/green' +href: 'http://colors.my-server.com/colors/blue' +``` + +As with all links, it at the the clients' discretion to follow them, and permissions and the ability to make a successful call to that link is not guaranteed soley by the existance of a relationship. + + +### Example + +The example below shows how relationships in the BitBucket API can be represented with the proposed OAI link scheme. This example uses `operationId` values to link responses to possible operations. + +```yaml +paths: + /2.0/users/{username}: + get: + operationId: getUserByName + parameters: + - name: username + type: string + in: path + required: true + responses: + 200: + description: The User + schema: + $ref: '#/components/definitions/user' + links: + userRepositories: + $ref: '#/components/links/UserRepositories' + /2.0/repositories/{username}: + get: + operationId: getRepositoriesByOwner + parameters: + - name: username + type: string + in: path + required: true + responses: + 200: + description: repositories owned by the supplied user + schema: + type: array + items: + $ref: '#/components/definitions/repository' + links: + userRepository: + $ref: '#/components/links/UserRepository' + /2.0/repositories/{username}/{slug}: + get: + operationId: getRepository + parameters: + - name: username + type: string + in: path + required: true + - name: slug + type: string + in: path + required: true + responses: + 200: + description: The repository + schema: + $ref: '#/components/definitions/repository' + links: + repositoryPullRequests: + $ref: '#/components/links/RepositoryPullRequests' + /2.0/repositories/{username}/{slug}/pullrequests: + get: + operationId: getPullRequestsByRepository + parameters: + - name: username + type: string + in: path + required: true + - name: slug + type: string + in: path + required: true + - name: state + type: string + in: query + enum: + - open + - merged + - declined + responses: + 200: + description: an array of pull request objects + schema: + type: array + items: + $ref: '#/components/definitions/pullrequest' + /2.0/repositories/{username}/{slug}/pullrequests/{pid}: + get: + operationId: getPullRequestsById + parameters: + - name: username + type: string + in: path + required: true + - name: slug + type: string + in: path + required: true + - name: pid + type: string + in: path + required: true + responses: + 200: + description: a pull request object + schema: + $ref: '#/components/definitions/pullrequest' + links: + $ref: '#/components/links/PullRequestMerge' + /2.0/repositories/{username}/{slug}/pullrequests/{pid}/merge: + post: + operationId: mergePullRequest + parameters: + - name: username + type: string + in: path + required: true + - name: slug + type: string + in: path + required: true + - name: pid + type: string + in: path + required: true + responses: + 204: + description: the PR was successfully merged +components: + links: + UserRepositories: + # returns array of '#/components/definitions/repository' + operationId: getRepositoriesByOwner + parameters: + username: $response.username + UserRepository: + # returns '#/components/definitions/repository' + operationId: getRepository + parameters: + username: $response.owner.username + slug: $response.slug + RepositoryPullRequests: + # returns '#/components/definitions/pullrequest' + operationId: getPullRequestsByRepository + params: + username: $response.owner.username + slug: $response.slug + PullRequestMerge: + # executes /2.0/repositories/{username}/{slug}/pullrequests/{pid}/merge + operationId: mergePullRequest + parameters: + username: $response.user.username # Should be $response.author.username? + slug: $response.repository.slug + pid: $response.id + definitions: + user: + type: object + properties: + username: + type: string + uuid: + type: string + repository: + type: object + properties: + slug: + type: string + owner: + $ref: '#/components/definitions/user' + pullrequest: + type: object + properties: + id: + type: integer + title: + type: string + repository: + $ref: '#/components/definitions/repository' + author: + $ref: '#/components/definitions/user' +``` + +As references to `operationId` may not be possible (the `operationId` is an optional value), references may also be made through a relative `href`: + +```yaml +components: + links: + UserRepositories: + # returns array of '#/components/definitions/repository' + href: '/2.0/repositories/{$response.username}' +``` + +or an absolute `href`: + +```yaml +components: + links: + UserRepositories: + # returns array of '#/components/definitions/repository' + href: 'https://na2.gigantic-server.com/2.0/repositories/{$response.username}' +``` + + +### Link Parameters +Using the `operationId` to reference an operation in the definition has many benefits, including the ability to define media-type options, security requirements, response and error payloads. Many operations require parameters to be passed, and these may be dynamic depending on the response itself. + +To specify parameters required by the operation, we can use a **Link Parameters Object**. This object contains parameter names along with static or dynamic valus: + +```yaml +paths: + /user/{username}: # ... + /user/{username}/commits: + get: + operationId: userCommitHistory + parameters: + - name: username + in: path + type: string + required: true + - name: page + type: integer + format: int32 + required: true + responses: { ... } +components: + links: + UserCommitHistory: + operationId: userCommitHistory + parameters: + username: $response.user.username + page: 0 +``` + +In the above, the link for `UserCommitHistory` points to the operation `getUserCommitHistory`, and passes the `username` value from the response payload as well as the static scalar value `0`. + #### Header Object Field Name | Type | Description