How to correctly specify OpenAPI 3 Link object based on response header - openapi

I am working on a REST API defined by an OpenAPI specification document; one thing that is currently missing is the use of Links to define the connection options between endpoints, and I can't figure out how to specify what I want.
For example, imagine a POST /widgets endpoint that returns a 201 Created response, and sets the URI of the created widget in the Location response header. My definition is currently something like this:
paths:
/widgets:
post:
operationId: addWidget
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AddWidget'
responses:
'201':
headers:
Location:
$ref: '#/components/headers/Location'
'400':
$ref: '#/components/responses/BadRequest'
/widgets/{widgetId}:
get:
operationId: getWidgetById
parameters:
- $ref: '#/components/parameters/WidgetId'
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Widget'
The OpenAPI documentation (https://swagger.io/docs/specification/links/) shows how to get the raw value of the Location header, but that's a URI, and the body of the 201 response is empty e.g.
links:
getWidgetById:
operationId: getWidgetById
parameters:
employeeId: '$response.headers.location'
So how can I extract e.g. a GUID from Location: https://my.api.com/widgets/3a32d587-56ca-4dea-81b4-01ed9cdf41c0/ to insert that into the employeeId parameter for the link?

Related

How do I override example for specific properties in components in OpenAPI?

Here's the minimal working example:
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
paths:
/pets:
get:
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
components:
schemas:
Pet:
type: object
required:
- customName
properties:
genericName:
type: string
example: Alex
customName:
type: string
example: Ivanov
I would like to use a component Pet for the spec above yet I would like to be able to override an example for customName (the reason is it's like a URL in my real example and I'd like it be specific and it's based on the current resource but the component itself is shared among multiple resources if that makes sense).
I tried #1:
...
application/json:
schema:
$ref: "#/components/schemas/Pet"
example:
customName: IvanovOverride
components:
...
application/json:
schema:
allOf:
- $ref: "#/components/schemas/Pet"
example:
properties:
customName: IvanovOverride
and #3:
schema:
allOf:
- $ref: "#/components/schemas/Pet"
- properties:
customName:
example: IvanovOverride
but they all didn't work on Swagger Editor (the doc always showed "Ivanov" as an example).
If you use OpenAPI 3.1, and you have the necessary tooling supporting it, you can use the $dynamicAnchor and $dynamicRef for solving the problem.
Example:
openapi: "3.1.0"
info:
version: 1.0.0
title: Swagger Petstore
paths:
/pets:
get:
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/PetWithFirstExampleName"
components:
schemas:
PetWithFirstExampleName:
properties:
customName:
example: firstExampleName
$dynamicAnchor: customNameExample
$ref: "#/components/schemas/Pet"
Pet:
type: object
$dynamicRef: customNameExample
required:
- customName
properties:
genericName:
type: string
example: Alex
customName:
type: string
# example is provided by the schema referenced by $dynamicRef
Note: this is a quite new feature of json schema and OpenAPI, so you can easily run into problems with the implementations.
Note 2: yours is an approximately similar usecase as this one in the official json schema test suite.

In OpenAPI 3, how to document that an Accept header with a specified value is necessary on request in order for a successful API call?

For a legacy API that I document in order for a successful authentication I need to provide the following headers:
X-Access-Token: {token}
Accept: application/json; version=public/v2
For the token part I need document it via:
openapi: 3.0.0
info:
version: "v2"
title: Company App Public Api
description: Integrate your platform with company app website
components:
securitySchemes:
ApiKey:
type: 'apiKey'
in: 'header'
name: 'X-Access-Token'
security:
- ApiKey: []
But how I can document that also for an authentication I need to provide an Accept: application/json; version=public/v2. The Accept header must contain the application/json; version=public/v2 anything else returns 406 Not Acceptable header.
Also, the header Accept with value application/json; version=public/v2 should be in my request. The response header is always application/json.
Do you know how I can document that?
In OpenAPI 3.0, the request header Accept and the response header Content-Type are both defined as responses.<code>.content.<Accept value>. This needs to be defined in every operation.
paths:
/something:
get:
responses:
'200':
description: Successful operation
content:
'application/json; version=public/v2': # <-----
schema:
...
'406':
description: Invalid media type was specified in the `Accept` header (should be `application/json; version=public/v2`)
In order to specify that you should perform a http request using the application/json; version=public/v2 accept header you should document it like this:
openapi: 3.0.0
info:
version: "v2"
title: Company App Public Api
description: Integrate your platform with company app website
components:
securitySchemes:
ApiKey:
type: 'apiKey'
in: 'header'
name: 'X-Access-Token'
responses:
406:
description: "Is returned once `Accept` header has not been provided or does not contain the `application/json; version=public/v2` value."
content:
'application/json':
schema:
type: object
properties:
error:
type: 'boolean'
type:
type: 'string'
message:
type: 'string'
description: "Your access token is either missing or incorrect. Please check the X-Access-Token header and try again."
401:
description: "Is returned once `X-Access-Token` has not been provided"
content:
'application/json':
schema:
type: object
properties:
error:
type: 'boolean'
type:
type: 'string'
message:
description: "Your access token is either missing or incorrect. Please check the X-Access-Token header and try again."
security:
- ApiKey: []
paths:
/myendpoint:
put:
requestBody:
required: true
content:
'application/json; version=public/v2': {}
responses:
200:
'application/json':
#your response jhere as documented in
406:
$ref: '#/components/responses/406'
401:
$ref: '#/components/responses/401'
So with this approach you tell in the documentation that the request should be a put one with the Accept header application/json; version=public/v2 with any (or no) parameters.
Though for get requests requestBody is not a valid definition.

How to vary requestBody type based on a path parameter in OpenAPI 3.0?

In OpenAPI 2.0, in: body and in: formData parameters cannot exist together for the same operation, according to Swagger send body and formData parameter and OpenAPI 2.0 Specification. That makes sense.
But I'm using OpenAPI 3.0 and I wonder if there is a way to switch requestBody according to a path parameter? When store is path1, requestBody should use content with application/json; when store is path2, requestBody should use content with multipart/form-data.
/customs/{store}:
post:
description: Customs server calls Nomad to receive the filing result of one
order
operationId: post_customs_callback
parameters:
- description: ID of the store.
explode: true
in: path
name: store
required: true
schema:
type: string
style: simple
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties: # Request parts
openReq:
type: string
# application/json:
# schema:
# type: string
description: Order details
OpenAPI Specification does not have a way to vary request/response body based on specific parameter values. However, in your scenario you can use two non-parameterized paths instead – /customs/path1 for JSON requests and /customs/path2 for multipart requests.
openapi: 3.0.0
...
paths:
/customs/path1:
post:
...
requestBody:
required: true
content:
application/json:
schema:
...
/customs/path2:
post:
...
requestBody:
required: true
content:
multipart/form-data:
schema:
...

Why does Swagger mark the GET requests as duplicate mapping ke?

I have this 2 GET requests one is /report and the second one is /report/{id}.
paths:
/report:
get:
operationId: getReportsList
responses:
'200':
description: List of reports
content:
application/json:
schema:
items:
$ref: '#/components/schemas/Metadata'
get:
operationId: getReportById
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
description: Report is finished and returned
content:
application/json:
schema:
$ref: '#/components/schemas/Report'
SwaggerHub shows an error against second GET with a description
duplicated mapping key
Could you tell me what am I doing wrong and why Swagger does think that URLs with and without path variable are the same?
Add a new path where explicitly append your path variable /report/{id} for the second GET.

Validate OpenAPI response with dredd

I have an OpenAPI v3 specification file with the following (showing just fragments):
paths:
/global/name:
get:
description: Some description
tags:
- Global settings
operationId: getGlobalSettingsName
responses:
# Response code
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/globalSettingsName'
components:
schemas:
globalSettingsName:
type: object
properties:
name:
type: integer
description: 'ID'
example: 1
required:
- name
but the server response is:
{
"name": "somestring"
}
Note the name property type is integer and in the server response, it is a string (on purpose) but dredd request passes (success).
Doesn't dredd check for response property types?
I redefined the response as string (not JSON):
responses:
# Response code
'200':
description: Successful response
content:
application/json:
schema:
type: string
and dredd doesn't complain about either.
I even changed the property of the schema:
globalSettingsName:
type: object
properties:
www:
type: string
description: 'some description'
example: 'somestring'
required:
- www
And same (success) result when it is expected to fail.
Aren't these validation supported by dredd? Am I using specification wrong?
It results that the current version (8.0.5) only supports example value in content: https://github.com/apiaryio/dredd/issues/1281