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
...
Related
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?
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'
I authenticate on the server by feeding req.user with an instance of cds.User, and I add some attributes:
User {
id: '110226363079182595683',
attr: { name: 'depth1', email: 'depth1#protonmail.com' },
_roles: { 'identified-user': true, 'authenticated-user': true }
}
This allows me to call my CDS services with an authenticated user.
It works well.
Then, I have in my CDS schema an entity :
entity Comments {
key ID : Integer;
project : Association to Projects;
title : String;
text : String;
CreatedBy : String #cds.on.insert : $user;
CreatedByName : String #cds.on.insert : $user.name;
}
My schema on an SQLite database.
I start the server, I launch a UI5 application which allows to insert comments in OData V4 and here is what happens:
HTTP request:
--batch_id-1642708209182-45
Content-Type:application/http
Content-Transfer-Encoding:binary
POST Projects(1)/comments HTTP/1.1
Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true
Accept-Language:fr-FR
Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true
{"ID":0,"text":"test comment"}
--batch_id-1642708209182-45--
Group ID: $auto
Server Log:
[cds] - > CREATE Projects(1)/comments
HTTP Response:
--batch_id-1642708209182-45
content-type: application/http
content-transfer-encoding: binary
HTTP/1.1 201 Created
odata-version: 4.0
content-type: application/json;odata.metadata=minimal;IEEE754Compatible=true
location: Comments(101)
{"#odata.context":"../$metadata#Comments/$entity","ID":101,"project_ID":1,"title":null,"text":"test comment","CreatedBy":"110226363079182595683","CreatedByName":"depth1"}
--batch_id-1642708209182-45--
HTTP Request:
--batch_id-1642708209355-46
Content-Type:application/http
Content-Transfer-Encoding:binary
GET Projects(1)/comments(101)?$select=CreatedByName,ID,text HTTP/1.1
Accept:application/json;odata.metadata=minimal;IEEE754Compatible=true
Accept-Language:fr-FR
Content-Type:application/json;charset=UTF-8;IEEE754Compatible=true
--batch_id-1642708209355-46--
Group ID: $auto
Server log
[cds] - > READ Projects(1)/comments(101) { '$select': 'CreatedByName,ID,text' }
HTTP Response
--batch_id-1642708209355-46
content-type: application/http
content-transfer-encoding: binary
HTTP/1.1 200 OK
odata-version: 4.0
content-type: application/json;odata.metadata=minimal;IEEE754Compatible=true
{"#odata.context":"../$metadata#Comments(CreatedByName,ID,text)/$entity","CreatedByName":null,"ID":101,"text":"aaa"}
--batch_id-1642708209355-46--
In my Database, CreatedBy is filled but not CreatedByName.
Also in the Create request i got the CreatedByName filled by the server and returned it's really strange.
How can i insert some cds.User attributes to the database ?!
Thank you !
Oww
I found a solution ! By adding a behavior in service.js
const cds = require('#sap/cds')
module.exports = cds.service.impl(function() {
this.before('CREATE', 'Comments', fillData)
})
async function fillData(req) {
req.data.CreatedByName = req.user.attr.name;
}
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).
incompatibility when running dart rpc and shelf (with shelf_rpc)
related to headers which are lists (and not Strings).
It seems that there is an incompatibility when running dart rpc and shelf (with shelf_rpc)
related to headers which are lists (and not Strings).
Error thrown is ( for shelf[0.5.7], shelf_rpc[0.0.3], rpc[0.4.2]: ):
Error thrown by handler.
type 'List' is not a subtype of type 'String' of 'value'.
package:collection/src/canonicalized_map.dart 66:30 CanonicalizedMap.[]=
package:collection/src/canonicalized_map.dart 71:39 CanonicalizedMap.addAll.<fn>
dart:collection _CompactLinkedHashMap.forEach
package:collection/src/canonicalized_map.dart 71:18 CanonicalizedMap.addAll
package:collection/src/canonicalized_map.dart 57:11 CanonicalizedMap.CanonicalizedMap.from
package:shelf/src/response.dart 215:9 Response.Response
package:shelf_rpc/shelf_rpc.dart 18:24 createRpcHandler.<fn>.<fn>
A workaround around this problem is to change shelf_rpc.dart to replace the Lists by Strings:
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "package:shelf/shelf.dart";
import "package:rpc/rpc.dart";
/// Creates a Shelf [Handler] that translates Shelf [Request]s to rpc's
/// [HttpApiRequest] executes the request on the given [ApiServer] and then
/// translates the returned rpc's [HttpApiResponse] to a Shelf [Response].
Handler createRpcHandler(ApiServer apiServer) {
return (Request request) {
try {
var apiRequest = new HttpApiRequest(request.method, request.requestedUri,
request.headers, request.read());
return apiServer.handleHttpApiRequest(apiRequest).then(
(apiResponse) {
// EXTRA: print and work-around
printHeaders(apiResponse.headers, true);
printHeaders(apiResponse.headers, false);
// EXTRA <end>
return new Response(apiResponse.status, body: apiResponse.body,
headers: apiResponse.headers);
});
} catch (e) {
// Should never happen since the apiServer.handleHttpRequest method
// always returns a response.
return new Response.internalServerError(body: e.toString());
}
};
}
// EXTRA WORKAROUND: print headers & replace Lists by Strings
printHeaders(Map headers, bool replaceListsBytStrings) {
print('--HEADERS start---');
headers.forEach(
(key, value) {
print('key: $key - value: $value - type: ${value.runtimeType}');
if ( (replaceListsBytStrings) && (value is List) ) {
String str = value.toString().substring(1, value.toString().length-1);
headers[key] = str;
}
});
print('--HEADERS end---');
}
Output:
--HEADERS start---
key: content-type - value: application/json; charset=utf-8 - type: String
key: cache-control - value: no-cache, no-store, must-revalidate - type: String
key: pragma - value: no-cache - type: String
key: expires - value: 0 - type: String
key: access-control-allow-credentials - value: true - type: String
key: access-control-allow-origin - value: * - type: String
key: allow - value: [GET] - type: List
key: access-control-allow-methods - value: [GET] - type: List
key: access-control-allow-headers - value: origin, x-requested-with, content-type, accept - type: String
key: Access-Control-Allow-Headers - value: null,Authorization, content-type - type: String
--HEADERS end---
--HEADERS start---
key: content-type - value: application/json; charset=utf-8 - type: String
key: cache-control - value: no-cache, no-store, must-revalidate - type: String
key: pragma - value: no-cache - type: String
key: expires - value: 0 - type: String
key: access-control-allow-credentials - value: true - type: String
key: access-control-allow-origin - value: * - type: String
key: allow - value: GET - type: String
key: access-control-allow-methods - value: GET - type: String
key: access-control-allow-headers - value: origin, x-requested-with, content-type, accept - type: String
key: Access-Control-Allow-Headers - value: null,Authorization, content-type - type: String
--HEADERS end---
This should be fixed in the latest version of the Dart RPC package (v0.4.3). Please try it out and let me know how it works.
/gustav