I'm trying to migrate from Springfox to springdoc for our Swagger page, and there is one endpoint that I am having a hard time getting working with springdoc. It is mimicking a OAuth2 token endpoint, taking in an application/x-www-form-urlencoded request body with different grant types allowed. I have the generated openapi documentation below. According to the Swagger page, the free form data should be allowed when using schema of type object. However, when I pass in the example values that worked on Springfox and swagger 2 (grant_type=authorization_code&code=xxxxxxxxxx&client_id=xxxxxxxxxx), the request is built out like this (note the body):
curl -X 'POST' \
'http://localhost:8080/v1/token' \
-H 'accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d '0=g&1=r&2=a&3=n&4=t&5=_&6=t&7=y&8=p&9=e&10=%3D&11=a&12=u&13=t&14=h&15=o&16=r&17=i&18=z&19=a&20=t&21=i&22=o&23=n&24=_&25=c&26=o&27=d&28=e&29=%26&30=c&31=o&32=d&33=e&34=%3D&35=x&36=x&37=x&38=x&39=x&40=x&41=x&42=x&43=x&44=x&45=%26&46=c&47=l&48=i&49=e&50=n&51=t&52=_&53=i&54=d&55=%3D&56=x&57=x&58=x&59=x&60=x&61=x&62=x&63=x&64=x&65=x'
Is there something that I am doing wrong in the openapi yaml, or am I putting the request body in incorrectly on the swagger page?
Swagger documentation:
OpenAPI YAML to be used at https://editor.swagger.io/
openapi: 3.0.1
info:
title: Test API
description: Testing
version: "1.0"
servers:
- url: http://localhost:8080
description: Generated server url
security:
- api: []
paths:
/v1/token:
post:
tags:
- token-controller
description: Oauth 2 Access Token.
operationId: getOauthAccessToken
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
examples:
authorization_code grant type:
description: authorization_code grant type
value: grant_type=authorization_code&code=xxxxxxxxxx&client_id=xxxxxxxxxx
client_credentials grant type:
description: client_credentials grant type
value: grant_type=client_credentials&client_id=xxxxxxxxxx&client_secret=xxxxxxxxxx
refresh_token grant type:
description: refresh_token grant type
value: grant_type=refresh_token&refresh_token=xxxxxxxxxx
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/OauthAccessTokenResponseView_V1'
components:
schemas:
OauthAccessTokenResponseView_V1:
type: object
properties:
scope:
type: string
access_token:
type: string
refresh_token:
type: string
token_type:
type: string
expires_in:
type: integer
format: int64
description: 'The Oauth 2 Access Token response: https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/'
securitySchemes:
api:
type: http
scheme: bearer
Your definition looks fine. This is a bug (or limitation?) in Swagger UI related to OpenAPI 3 examples keyword and form data. Please report it in the issue tracker: https://github.com/swagger-api/swagger-ui/issues
I could not find a working way to provide multiple examples for form data.
From the documentation point of view, I would recommend updating the request body schema to define the exact expected properties. Below is one possible variant that uses oneOf and property-level example values. But unfortunately there are other known issues with the rendering and "try it out" for form data with oneOf.
requestBody:
content:
application/x-www-form-urlencoded:
schema:
oneOf:
- $ref: '#/components/schemas/AuthorizationCodeTokenRequest'
- $ref: '#/components/schemas/ClientCredentialsTokenRequest'
- $ref: '#/components/schemas/RefreshTokenRequest'
...
components:
schemas:
AuthorizationCodeTokenRequest:
type: object
required:
- grant_type
- code
- client_id
properties:
grant_type:
type: string
enum: [authorization_code]
code:
type: string
example: xxxxxxxxxx
client_id:
type: string
example: xxxxxxxxxx
ClientCredentialsTokenRequest:
type: object
required:
- grant_type
- client_id
- client_secret
properties:
grant_type:
type: string
enum: [client_credentials]
client_id:
type: string
example: xxxxxxxxxx
client_secret:
type: string
format: password
example: xxxxxxxxxx
RefreshTokenRequest:
type: object
required:
- grant_type
- refresh_token
properties:
grant_type:
type: string
enum: [refresh_token]
refresh_token:
type: string
format: password
example: xxxxxxxxxx
Do you actually need to document the payload for the token endpoint? If it's a standard OAuth 2.0 token endpoint as per RFC 6749, you could define it in securitySchemes instead:
paths:
/something:
get:
description: One of the endpoints that require OAuth Bearer token.
security:
- oauth2: [] # <-----
responses:
...
components:
securitySchemes:
oauth2: # <-----
type: oauth2
flows:
authorizationCode:
authorizationUrl: '???' # TODO
tokenUrl: /v1/token
refreshUrl: '???' # TODO
scopes: {}
clientCredentials:
tokenUrl: /v1/token
refreshUrl: '???' # TODO
scopes: {}
i am making openapi.yaml till now as well as deploying my test API's on the google cloud endpoints is working but now i made some changes i am sending parameter in body to the get api (e.g email) and getting some response but actually on the local it is working fine with postman after deploying openapi.yaml file it is not working on the google cloud endponits portal
So, anybody has any solution or answers for this so please help me
For safety i am also sharing error screenshot also y code snippet
"/api/getRecords":
get:
description: "Get All Records Details."
operationId: "getRecords"
produces:
- "application/json"
parameters:
- description: "Message to getRecords"
in: query
name: getRecords
type: object
required: false
schema:
$ref: "#/definitions/echoMessage"
responses:
200:
Also,
Try your code like this :
# [START swagger]
swagger: "2.0"
info:
description: "A simple Google Cloud Endpoints API example."
title: "Endpoints Example"
version: "1.0.0"
host: "abc.appspot.com"
# [END swagger]
parameters:
email:
name: email
in: query
type: string
required: true
Then use shorthand syntax in the path:
path:
"/api/getRecords":
get:
description: "Get All Records Details."
operationId: "getRecords"
parameters:
- $ref: "#/parameters/email"
responses:
200:
description: "Get records details"
schema:
$ref: "#/definitions/postMessage"
It will work.
I'm writing the swagger under OAS 3.0.2 specification. And wondering if it is possible to set the authorization value (BearerAuth) through the operation return value.
Now I need to call the api/login first and then copy return token and paste to authorize panel. Is there have better way to auto link the value between operation and security?
I've tried to use Links, but I am not sure that support on security. (The official document do not mention the way to implement on security)
paths:
/login:
post:
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
account:
type: string
password:
type: string
responses:
'200':
description: data.apiToken
content:
application/json:
schema:
type: object
properties:
data:
type: object
description: data
properties:
apiToken:
type: string
description: I need this as authorization value
links:
ApiToken:
operationId: apiToken
parameters:
apiToken: '$response.body#/data.apiToken'
The login was success, and response body like:
{
"data":{
"apiToken": "xxxxxx"
}
}
But next step I have no idea how to do. The response is 401 because token not being sent in headers (...I'm not surprise).
/someapi:
get:
summary: This API need auth to get data
operationId: apiToken
security:
- BearerAuth: [apiToken]
responses:
'401':
description: Not work
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
If I copy/paste manually, it could be authorized successfully. Is there any way to solve this issue or just not support this feature right now? Thank you so much.
I'm trying to run the following code:
/v1/test/{id}:
x-swagger-router-controller: Security
get:
operationId: test
description: "Test jwt middleware and multiple paths"
security:
- JWT: []
parameters:
- name: "id"
in: "path"
description: "ID of user"
required: true
type: "integer"
responses:
"200":
description: "Success"
schema:
$ref: "#/definitions/LoginSuccess"
"403":
description: "Access Denied"
schema:
$ref: "#/definitions/Error"
/v2/test/{id}:
$ref: "#/paths/~1v1~1test~1{id}"
But i'm receiving the following error:
API Errors:
#/paths/~1v2~1test~1{id}/$ref: Path could not be resolved:
/paths/~1v1~1test~1{id}
How can i fix this?
In this particular case what I really needed to achieve was to be able to version my API especially where not all methods had a newer version yet ie where for example /api/v1/method and /api/v2/method were still destined for the same function.
I thus solved it as follows
parameters:
- name: version
in: path
description: Version number of API
required: true
type: string
enum: &APIVERSION
- v1
- v2
In this way both v1 and v2 went to the same place. I can also add v3 etc to the enum which is reusable by different paths as enum: *APIVERSION
I'm preparing my API documentation by doing it per hand and not auto generated. There I have headers that should be sent to all APIs and don't know if it is possible to define parameters globally for the whole API or not?
Some of these headers are static and some has to be set when call to API is made, but they are all the same in all APIs, I don't want to copy and paste parameters for each API and each method as this will not be maintainable in the future.
I saw the static headers by API definition but there is no single document for how somebody can set them or use them.
Is this possible at all or not?
It depends on what kind of parameters they are.
The examples below are in YAML (for readability), but you can use http://www.json2yaml.com to convert them to JSON.
Security-related parameters: Authorization header, API keys, etc.
Parameters used for authentication and authorization, such as the Authorization header, API key, pair of API keys, etc. should be defined as security schemes rather than parameters.
In your example, the X-ACCOUNT looks like an API key, so you can use:
swagger: "2.0"
...
securityDefinitions:
accountId:
type: apiKey
in: header
name: X-ACCOUNT
description: All requests must include the `X-ACCOUNT` header containing your account ID.
# Apply the "X-ACCOUNT" header globally to all paths and operations
security:
- accountId: []
or in OpenAPI 3.0:
openapi: 3.0.0
...
components:
securitySchemes:
accountId:
type: apiKey
in: header
name: X-ACCOUNT
description: All requests must include the `X-ACCOUNT` header containing your account ID.
# Apply the "X-ACCOUNT" header globally to all paths and operations
security:
- accountId: []
Tools may handle security schemes parameters differently than generic parameters. For example, Swagger UI won't list API keys among operation parameters; instead, it will display the "Authorize" button where your users can enter their API key.
Generic parameters: offset, limit, resource IDs, etc.
OpenAPI 2.0 and 3.0 do not have a concept of global parameters. There are existing feature requests:
Allow for responses and parameters shared across all endpoints
Group multiple parameter definitions for better maintainability
The most you can do is define these parameters in the global parameters section (in OpenAPI 2.0) or the components/parameters section (in OpenAPI 3.0) and then $ref all parameters explicitly in each operation. The drawback is that you need to duplicate the $refs in each operation.
swagger: "2.0"
...
paths:
/users:
get:
parameters:
- $ref: '#/parameters/offset'
- $ref: '#/parameters/limit'
...
/organizations:
get:
parameters:
- $ref: '#/parameters/offset'
- $ref: '#/parameters/limit'
...
parameters:
offset:
in: query
name: offset
type: integer
minimum: 0
limit:
in: query
name: limit
type: integer
minimum: 1
maximum: 50
To reduce code duplication somewhat, parameters that apply to all operations on a path can be defined on the path level rather than inside operations.
paths:
/foo:
# These parameters apply to both GET and POST
parameters:
- $ref: '#/parameters/some_param'
- $ref: '#/parameters/another_param'
get:
...
post:
...
If you're talking about header parameters sent by consumer when calling the API...
You can at least define them once and for all in parameters sections then only reference them when needed.
In the example below:
CommonPathParameterHeader, ReusableParameterHeader and AnotherReusableParameterHeader are defined once and for all in parameterson the root of the document and can be used in any parameters list
CommonPathParameterHeaderis referenced in parameters section of /resources and /other-resources paths, meaning that ALL operation of these paths need this header
ReusableParameterHeader is referenced in get /resources meaning that it's needed on this operation
Same thing for AnotherReusableParameterHeader in get /other-resources
Example:
swagger: '2.0'
info:
version: 1.0.0
title: Header API
description: A simple API to learn how you can define headers
parameters:
CommonPathParameterHeader:
name: COMMON-PARAMETER-HEADER
type: string
in: header
required: true
ReusableParameterHeader:
name: REUSABLE-PARAMETER-HEADER
type: string
in: header
required: true
AnotherReusableParameterHeader:
name: ANOTHER-REUSABLE-PARAMETER-HEADER
type: string
in: header
required: true
paths:
/resources:
parameters:
- $ref: '#/parameters/CommonPathParameterHeader'
get:
parameters:
- $ref: '#/parameters/ReusableParameterHeader'
responses:
'200':
description: gets some resources
/other-resources:
parameters:
- $ref: '#/parameters/CommonPathParameterHeader'
get:
parameters:
- $ref: '#/parameters/AnotherReusableParameterHeader'
responses:
'200':
description: gets some other resources
post:
responses:
'204':
description: Succesfully created.
If you're talking about header sent with each API response...
Unfortunately you cannot define reusable response headers.
But at least you can define a reusable response containing these headers for common HTTP responses such as a 500 error.
Example:
swagger: '2.0'
info:
version: 1.0.0
title: Header API
description: A simple API to learn how you can define headers
parameters:
CommonPathParameterHeader:
name: COMMON-PARAMETER-HEADER
type: string
in: header
required: true
ReusableParameterHeader:
name: REUSABLE-PARAMETER-HEADER
type: string
in: header
required: true
AnotherReusableParameterHeader:
name: ANOTHER-REUSABLE-PARAMETER-HEADER
type: string
in: header
required: true
paths:
/resources:
parameters:
- $ref: '#/parameters/CommonPathParameterHeader'
get:
parameters:
- $ref: '#/parameters/ReusableParameterHeader'
responses:
'200':
description: gets some resources
headers:
X-Rate-Limit-Remaining:
type: integer
X-Rate-Limit-Reset:
type: string
format: date-time
/other-resources:
parameters:
- $ref: '#/parameters/CommonPathParameterHeader'
get:
parameters:
- $ref: '#/parameters/AnotherReusableParameterHeader'
responses:
'200':
description: gets some other resources
headers:
X-Rate-Limit-Remaining:
type: integer
X-Rate-Limit-Reset:
type: string
format: date-time
post:
responses:
'204':
description: Succesfully created.
headers:
X-Rate-Limit-Remaining:
type: integer
X-Rate-Limit-Reset:
type: string
format: date-time
'500':
$ref: '#/responses/Standard500ErrorResponse'
responses:
Standard500ErrorResponse:
description: An unexpected error occured.
headers:
X-Rate-Limit-Remaining:
type: integer
X-Rate-Limit-Reset:
type: string
format: date-time
About OpenAPI (fka. Swagger) Next version
The OpenAPI spec (fka. Swagger) will evolve and include the definition of reusable response headers among other things (cf. https://github.com/OAI/OpenAPI-Specification/issues/563).
As per this Swagger issue comment, support for global parameters (including header parameters) is not planned in foreseeable future, but to limit the repetition you should use parameters references as in #Arnaud's answer (parameters: - $ref: '#/parameters/paramX').
also wish some global variables, can be used anywhere.
( even in some examples, so can change common settings globally in ui ).
something like
"hello ${var1}" in shell or javascript.
searched docs many times, not found solution yet.
: (