Swagger - Multiple responses with the same http status code with drf-yasg - swagger

I have endpoint that may return json or excel file:
class ReportView(GenericAPIView):
#swagger_auto_schema(
responses={
200: openapi.Schema(
type=openapi.TYPE_FILE,
title='Report.xlsx'
),
200: openapi.Schema(
type=openapi.TYPE_OBJECT,
),
}
)
def get(self, request):
if request.query_params.get('format') == 'xlsx':
return excel response
return json response
How could I define two 200-responses at the same time?
I read some and found out about oneOf:
responses:
'200':
description: Success
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/ResponseOne'
- $ref: '#/components/schemas/ResponseTwo'
example: # <--- Workaround for Swagger UI < 3.39.0
foo: bar
How could I implement it with drf_yasg?

Related

swagger $ref, Could not resolve reference: Tried to resolve a relative URL, without having a basePath. path: 'user.yaml' basePath: 'undefined'

I changed $ref value several times,
but all of them reveal same error... help me plz
what's wrong?
swagger-ui error message
my directory image
swagger.js
import swaggereJsdoc from 'swagger-jsdoc';
const options = {
swaggerDefinition: {
info: {
title: 'User API',
version: '1.0.0',
description: 'User API with express',
},
host: 'localhost:8000',
// basePath: '/api',
},
apis: ['./routers/*.js', './swagger/*'],
};
export const specs = swaggereJsdoc(options);
user-router.js
/**
* #swagger
* /api/users:
* get:
* tags:
* - user
* description: users (array)
* produces:
* - application/json
* responses:
* '200':
* description: success getUsers
*
* schema:
* $ref: './swagger/user.yaml#/components/schemas/User'
*/
user.yaml
# /swagger/user.yml
components:
schemas:
User:
properties:
id:
type: integer
description: primary key
testing code before this question:
$ref: './swagger/user.yaml#/components/schemas/User'
$ref: '/swagger/user.yaml#/components/schemas/User'
$ref: 'swagger/user.yaml#/components/schemas/User'
$ref: './user.yaml#/components/schemas/User'
$ref: '/user.yaml#/components/schemas/User'
$ref: 'user.yaml#/components/schemas/User'

swagger ApiResponse example

I am trying to document an api error response with a example of the json body. I couldn't find an example or a fitting annotation. Playing around with the swagger editor I could at least get something that looks like the result I want to achieve.
responses:
'200' :
description: Request completed with no errors
examples:
application/json: {"result" : { "id": "blue" }}
libraries being is swagger-core 1.6.0
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<scope>compile</scope>
<version>1.6.0</version>
</dependency>
and the endpoints are created using jax-rs.
I did this to the endpoint
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK",
examples = #Example(value = #ExampleProperty(mediaType = "application/json", value = "{\"result\" : { \"id\": \"blue\" }}"))
)
})
public Response getResult(){}
The generated swagger.json doesn't have the desired
examples:
application/json: {"result" : { "id": "blue" }}
I tried also passing response = ApiResponse.class, Examples.class and Example.class but it doesn't change.
How can I do this with annotations?

Unable to connect a go-swagger parameter to a route

I have the following go-swagger annotation:
// swagger:parameters callbackReg
type registrationParms struct {
// Description of callback.
// in: query
// required: true
callback string
}
// OK indicates that the HTTP request was successful.
//
// swagger:response
type OK struct {
responseCode int
}
// BadRequest indicates that there was an error in
// the HTTP request.
//
// swagger:response
type BadRequest struct {
responseCode int
}
// swagger:route POST /eprouter/1.0/registration callbackReg
//
// Callback registration API.
//
// Registers a callback URL for unsolicited messages. A callback is registered for a given
// combination of message type (alarm, metric) and message encoding (Protobuf, XML).
//
// Schemes: http, https
//
// Responses:
// 200: OK
// 400: BadRequest
I generate the swagger YAML with swagger generate spec -o docs/swagger.yaml -w eprouter. The resulting YAML does not include the query parameter. My understanding is that the identifier callbackReg should tie the parameter structure to the route. What am I doing wrong?
The generated YAML:
info: {}
paths:
/eprouter/1.0/registration:
post:
description: |-
Registers a callback URL for unsolicited messages. A callback is registered for a given
combination of message type (alarm, metric) and message encoding (Protobuf, XML).
operationId: callbackReg
responses:
"200":
$ref: '#/responses/OK'
"400":
$ref: '#/responses/BadRequest'
schemes:
- http
- https
summary: Callback registration API.
responses:
BadRequest:
description: |-
BadRequest indicates that there was an error in
the HTTP request.
headers:
responseCode:
format: int64
type: integer
OK:
description: OK indicates that the HTTP request was successful.
headers:
responseCode:
format: int64
type: integer
swagger: "2.0"
The answer is that the values inside the parameter structures have to be exported (Capitalized).

Vertx + OpenAPI + OAuth2 security handler is calling twice

I'm a newbie in vertx world. I used this link for setting up my openapi routing: https://gist.github.com/slinkydeveloper/bdf5929c2506988d78fc08205089409a
Here is my sources:
api.yaml
#other endpoints...
/api/v1/protected/verification:
post:
summary: Summary
operationId: verification
security:
- ApiKey: []
tags:
- verification
responses:
'200':
description: User details
content:
application/json:
schema:
$ref: "#/components/schemas/User"
'401':
description: Unauthorized
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Exception"
#other endpoints ....
components:
securitySchemes:
ApiKey:
type: apiKey
name: Authorization
in: header
#other ones
OpenApi setup
OpenAPI3RouterFactory.createRouterFactoryFromFile(vertx, "src/main/resources/api.yaml") { openAPI3RouterFactoryAsyncResult ->
if (openAPI3RouterFactoryAsyncResult.succeeded()) {
// Spec loaded with success
val routerFactory = openAPI3RouterFactoryAsyncResult.result()
val keycloakJson = JsonObject("{\n" +
"\"realm\": \"master\",\n" +
"\"bearer-only\": true,\n" +
"\"auth-server-url\": \"http://localhost:8080/auth\",\n" +
"\"ssl-required\": \"external\",\n" +
"\"realm-public-key\": \"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn9Xya697ZVZzQidld4uCwRoWmLyWBDQQhn+EL1e0WDUWq9v39OBpM+HadkYlOMvfU1A8ohGZZVBkKV4w35gkm3bFPluCPsWxdcqD1NNF6BnIC6bRicgP/4beeehff8nWI3mFAfH7Q7Ik8mm8BDQYhOPRx50JBkDiIQ7AlAjNJ+5/eIj6Pt/eZSmMSk+vM4Xu64E0mCZfHpasdf!QsFGN+VPQejNBz7h9nEdi3swIIo0ot2+5PZGELX/2Dek7cY4RMKGb+rvU6ug3UvZHQ985KuubKsWMCs8+A80yWSoA6umw1DC5rAmc5jo/6giWawuFj5jFZRx69CcMSx1VaEJ5lS4LmAi5sXuQIDAQAB\",\n" +
"\"resource\": \"vertx\",\n" +
"\"use-resource-role-mappings\": true,\n" +
"\"credentials\": {\n" +
"\"secret\": \"asd1t747-3d11-456f-a553-d8e140cfaf58\"\n" +
"}\n" +
"}")
val oauth2 = KeycloakAuth
.create(vertx, OAuth2FlowType.AUTH_CODE, keycloakJson)
val handler = OAuth2AuthHandler.create(oauth2,
"http://localhost:8081/")
routerFactory.addSecurityHandler("ApiKey", handler)
handler?.setupCallback(routerFactory.router.route("/callback"))
routerFactory.addHandlerByOperationId(EndpointUriOperationId.SIGN_UP.endpoint, { routingContext -> signUpRouter?.signUp(routingContext) })
routerFactory.addHandlerByOperationId(EndpointUriOperationId.SIGN_IN.endpoint, { routingContext -> signInRouter?.signIn(routingContext) })
routerFactory.addHandlerByOperationId(EndpointUriOperationId.CONFIRM_ACCESS_CODE.endpoint, { routingContext -> signUpRouter?.confirmAccessCode(routingContext) })
routerFactory.addHandlerByOperationId(EndpointUriOperationId.IS_EMAIL_EXISTS.endpoint, { routingContext -> signUpRouter?.isEmailExists(routingContext) })
routerFactory.addHandlerByOperationId(EndpointUriOperationId.GET_ACCESS_CODE.endpoint, { routingContext -> signUpRouter?.getAccessCode(routingContext) })
routerFactory.addHandlerByOperationId(EndpointUriOperationId.VERIFICATION.endpoint, { routingContext -> signInRouter?.verification(routingContext) })
// Add an handler with a combination of HttpMethod and path
// Before router creation you can enable or disable mounting a default failure handler for ValidationException
// Now you have to generate the router
val router = routerFactory.router
router.route().handler(CorsHandler.create("*")
.allowedMethod(HttpMethod.GET)
.allowedMethod(HttpMethod.DELETE)
.allowedMethod(HttpMethod.POST)
.allowedMethod(HttpMethod.PUT)
.allowedMethod(HttpMethod.PATCH)
.allowedHeader("Authorization")
.allowedHeader("user-agent")
.allowedHeader("Access-Control-Request-Method")
.allowedHeader("Access-Control-Allow-Credentials")
.allowedHeader("Access-Control-Allow-Origin")
.allowedHeader("Access-Control-Allow-Headers")
.allowedHeader("Content-Type")
.allowedHeader("Content-Length")
.allowedHeader("X-Requested-With")
.allowedHeader("x-auth-token")
.allowedHeader("Location")
.exposedHeader("Location")
.exposedHeader("Content-Type")
.exposedHeader("Content-Length")
.exposedHeader("ETag")
.maxAgeSeconds(60))
// Now you can use your Router instance
val server = vertx.createHttpServer(HttpServerOptions().setPort(8081).setHost("0.0.0.0"))
server.requestHandler(router::accept).listen()
print("server is run\n")
} else {
// Something went wrong during router factory initialization
val exception = openAPI3RouterFactoryAsyncResult.cause()
print("OpenApiRoutingError! $exception")
}
}
My verification endpoint
fun verification(routingContext: RoutingContext) {
val map = (routingContext.user() as AccessTokenImpl).accessToken().map
val username = map.get("preferred_username").toString()
vertx.eventBus().send(SignInHandlerChannel.VERIFICATION.value(), username, { reply: AsyncResult<Message<String>> ->
if (reply.succeeded()) {
val result = JsonUtils.toPojo<MultiPosResponse<VerificationMapper>>(reply.result().body().toString())
routingContext
.response()
.putBrowserHeaders()
.setStatusCode(result.code!!)
.end(result.toJson())
} else{
routingContext
.response()
.putBrowserHeaders()
.setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code())
.end(reply.cause().toString())
}
})
}
The problem is when I send request to "/api/v1/protected/verification" endpoint my oauth2 handler works twice. First request processes by oauth handler(as must be) then passed to next, to my endpoint handler after that for some reason request passed to oauth2 handler again(as I think it shouldn't be). How can I fix this problem?

How to describe this POST JSON request body in OpenAPI (Swagger)?

I have a POST request that uses the following JSON request body. How can I describe this request body using OpenAPI (Swagger)?
{
"testapi":{
"testapiContext":{
"messageId":"kkkk8",
"messageDateTime":"2014-08-17T14:07:30+0530"
},
"testapiBody":{
"cameraServiceRq":{
"osType":"android",
"deviceType":"samsung555"
}
}
}
}
So far I tried the following, but I'm stuck at defining the body schema.
swagger: "2.0"
info:
version: 1.0.0
title: get camera
license:
name: MIT
host: localhost
basePath: /test/service
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/getCameraParameters:
post:
summary: Create new parameters
operationId: createnew
consumes:
- application/json
- application/xml
produces:
- application/json
- application/xml
parameters:
- name: pet
in: body
description: The pet JSON you want to post
schema: # <--- What do I write here?
required: true
responses:
200:
description: "200 response"
examples:
application/json:
{
"status": "Success"
}
I want to define the input body inline, as a sample for documentation.
I made it work with:
post:
consumes:
- application/json
produces:
- application/json
- text/xml
- text/html
parameters:
- name: body
in: body
required: true
schema:
# Body schema with atomic property examples
type: object
properties:
testapi:
type: object
properties:
messageId:
type: string
example: kkkk8
messageDateTime:
type: string
example: '2014-08-17T14:07:30+0530'
testapiBody:
type: object
properties:
cameraServiceRq:
type: object
properties:
osType:
type: string
example: android
deviceType:
type: string
example: samsung555
# Alternatively, we can use a schema-level example
example:
testapi:
testapiContext:
messageId: kkkk8
messageDateTime: '2014-08-17T14:07:30+0530'
testapiBody:
cameraServiceRq:
osType: android
deviceType: samsung555
The most readable way to include a multi line scalar into YAML is by using the block literal style. This requires you to change your JSON example only by using indentation (which will be removed if you retrieve the value for the key):
.
.
produces:
- application/json
example: |
{
"testapi": {
"testapiContext": {
"messageId": "kkkk8",
"messageDateTime": "2014-08-17T14:07:30+0530"
},
"testapiBody": {
"cameraServiceRq": {
"osType": "android",
"deviceType": "samsung555"
}
}
}
}
paths:
/getCameraParameters:
.
.
(for clarity you can put an extra newline or two before the paths scalar key, they get clipped by default on the literal block style scalars.
openapi version >= 3.0.0 allows for the use of a requestBody which would allow for request body definitions outside of parameters.
In your case it would look something like this:
...
requestBody:
description: The pet JSON you want to post
required: true
content:
application/json:
schema:
type: object
properties:
testapi:
type: object
properties:
messageId:
type: string
example: kkkk8
messageDateTime:
type: string
example: '2014-08-17T14:07:30+0530'
testapiBody:
type: object
properties:
cameraServiceRq:
type: object
properties:
osType:
type: string
example: android
deviceType:
type: string
example: samsung555
example:
testapi:
testapiContext:
messageId: kkkk8
messageDateTime: '2014-08-17T14:07:30+0530'
testapiBody:
cameraServiceRq:
osType: android
deviceType: samsung555
...

Resources