Swagger - Set the "response" based on "consumes" - swagger

Is it possible to specify the "response" based on the "consumes" option on Swagger?
My API can return "json" or "text" and I'd like that the "example value", when the response's status is 200 changes if the user selects from Response Content Type the option application/json or text/plain.
This is a piece of my swagger.json file:
{
"swagger": "2.0",
"produces": [
"application/json",
"text/plain"
],
"consumes" : [
"application\/json"
],
"paths": {
"/writer/1/": {
"get": {
"summary": "Get all writers",
"description": "Writer description.",
"tags": [
"writer"
],
"responses": {
"200": {
"description" : "successful operation",
"schema" : {
"$ref" : "#\/definitions\/writerResponse"
}
},
}
}
}
"definitions": {
"writerResponse": {
"properties": {
"meta": {
"type" :"object",
"schema" : {
"$ref" : "#\/definitions\/metaDefinition"
}
},
"data": {
"type" :"array",
"items": {
"$ref" : "#\/definitions\/writer"
}
}
}
},
"writer": {
"properties": {
"id": {
"type": "integer",
"description": "writer id.",
"example": "1477"
},
"short": {
"type": "string",
"description": "short description.",
"example": "short example"
},
"modified": {
"type": "string",
"description": "modified description.",
"example": "2016-05-21 22:58:36"
}
}
},
}
This is an example of the JSON output when user selects application/json:
{
"meta": {
"total": "1234",
"last_page": "967",
"per_page": "4000",
"current_page": "1",
"next_page_url": "http://localhost/api/<ws>/1?page=2",
"prev_page_url": "http://localhost/api/<ws>/1?page=1",
"from": "1",
"to": "4000"
},
"data": [
{
"id": "1",
"short": "TEST1",
"modified": "2011-03-07 14:17:23"
},
{
"id": "5",
"short": "TEST2",
"modified": "2015-05-26 12:39:45"
}
]
}
And this is the output when the user selects text/plain:
id|short|modified
1|TEST1|2011-03-07 14:17:23
5|TEST2|2015-05-26 12:39:45

Related

api-doc generated by Springfox not work with swagger-codegen

I'm testing if I can use the api-doc generated by springfox to generate Java client code through swagger-codegen.
I use the boot-swagger module from springfox-demos and the generated api-doc looks like below (pretty formatted)
{
"swagger": "2.0",
"info": {
"description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
"version": "2.0",
"title": "Springfox petstore API",
"termsOfService": "http://springfox.io",
"contact": {
"name": "springfox"
},
"license": {
"name": "Apache License Version 2.0",
"url": "https://github.com/springfox/springfox/blob/master/LICENSE"
}
},
"host": "localhost:8080",
"basePath": "/springfox",
"tags": [
{
"name": "category-controller",
"description": "Category Controller"
}
],
"paths": {
"/categories{?categories}": {
"post": {
"tags": [
"category-controller"
],
"summary": "map",
"operationId": "mapUsingPOST",
"consumes": [
"application/json"
],
"produces": [
"*/*"
],
"parameters": [
{
"name": "categories",
"in": "query",
"description": "categories",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"type": "string",
"enum": [
"ONE",
"TWO",
"THREE"
]
}
}
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
}
},
"/category/Resource{?someEnum}": {
"get": {
"tags": [
"category-controller"
],
"summary": "search",
"operationId": "searchUsingGET",
"produces": [
"*/*"
],
"parameters": [
{
"name": "someEnum",
"in": "query",
"description": "someEnum",
"required": true,
"type": "string",
"enum": [
"ONE",
"TWO",
"THREE"
]
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
}
},
"/category/map": {
"get": {
"tags": [
"category-controller"
],
"summary": "map",
"operationId": "mapUsingGET",
"produces": [
"*/*"
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/Pet"
}
}
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
}
},
"/category/{id}": {
"post": {
"tags": [
"category-controller"
],
"summary": "someOperation",
"operationId": "someOperationUsingPOST",
"consumes": [
"application/json"
],
"produces": [
"*/*"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "id",
"required": true,
"type": "integer",
"format": "int64"
},
{
"in": "body",
"name": "userId",
"description": "userId",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "OK"
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
}
},
"/category/{id}/map{?test}": {
"post": {
"tags": [
"category-controller"
],
"summary": "map",
"operationId": "mapUsingPOST_1",
"consumes": [
"application/json"
],
"produces": [
"*/*"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "id",
"required": true,
"type": "string"
},
{
"name": "test",
"in": "query",
"description": "test",
"required": true,
"items": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
],
"responses": {
"200": {
"description": "OK"
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
}
},
"/category/{id}/{userId}": {
"post": {
"tags": [
"category-controller"
],
"summary": "ignoredParam",
"operationId": "ignoredParamUsingPOST",
"consumes": [
"application/json"
],
"produces": [
"*/*"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "id",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "OK"
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
}
}
}
},
"definitions": {
"Category": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
},
"title": "Category"
},
"Map«string,Pet»": {
"type": "object",
"title": "Map«string,Pet»",
"additionalProperties": {
"$ref": "#/definitions/Pet"
}
},
"Pet": {
"type": "object",
"properties": {
"category": {
"$ref": "#/definitions/Category"
},
"id": {
"type": "integer",
"format": "int64"
},
"identifier": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"photoUrls": {
"type": "array",
"items": {
"type": "string"
}
},
"status": {
"type": "string",
"description": "pet status in the store",
"allowEmptyValue": false,
"enum": [
"available",
"pending",
"sold"
]
},
"tags": {
"type": "array",
"items": {
"$ref": "#/definitions/Tag"
}
}
},
"title": "Pet"
},
"Tag": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
}
},
"title": "Tag"
}
}
}
The code generation failed and it looks like the api-doc.json does not even fit for swagger specification.
I pasted the code into swagger editor, and it complains for a lot of errors such as
Semantic error at paths./categories{?categories}
Query strings in paths are not allowed.
Jump to line 18
So is it possible to generate client code from the api-doc.json generated by Springfox?
After reading the document of Springfox Reference Documentation, I have solved this issue!
Format like below is because by default springfox applies RFC 6570
./categories{?categories}
3.2. Configuration explained
An example of this would be two apis: First, http://example.org/findCustomersBy?name=Test to find customers by name. Per RFC 6570, this would be represented as http://example.org/findCustomersBy{?name}. Second, http://example.org/findCustomersBy?zip=76051 to find customers by zip. Per RFC 6570, this would be represented as http://example.org/findCustomersBy{?zip}.
One more issue I didn't mention in the question:
"Map«string,Pet»": { // The generated JSON contains special characters
"type": "object",
"title": "Map«string,Pet»",
"additionalProperties": {
"$ref": "#/definitions/Pet"
}
}
The document clearly mentioned the swagger-codegen situation:
6.8.3. Changing how Generic Types are Named
By default, types with generics will be labeled with '\u00ab'(<<), '\u00bb'(>>), and commas. This can be problematic with things like swagger-codegen. You can override this behavior by implementing your own GenericTypeNamingStrategy. For example, if you wanted List to be encoded as 'ListOfString' and Map to be encoded as 'MapOfStringAndObject' you could set the forCodeGeneration customization option to true during plugin customization:
docket.forCodeGeneration(true|false);
To summary, when we generate the docket in springfox for swagger-codegen, we need to specify the following switches:
new Docket(DocumentationType.SWAGGER_2)
.forCodeGeneration(true)
.enableUrlTemplating(false)

Swagger 3.0 reDoc Discriminator JSON

I'm currently writing swagger 3.0 documentation and using reDoc to render as nice UI for it. I have a few scenarios in my documentation where based on a previous properties enum I would want to display different schema object properties. Sadly I cant seam to figure out how to wire this together properly in my documentation. So far I have the following test endpoint:
{
"post": {
"operationId" : "test",
"summary": "test",
"description": "test",
"tags": [ "test" ],
"consumes": "application/json",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "./schemas/test1.json"
},
{
"$ref": "./schemas/test2.json"
}
],
"discriminator": {
"propertyName": "pet_type",
"mapping": {
"click": "./schemas/test1.json",
"open": "./schemas/test2.json"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Success"
}
}
}
}
The test1.json looks like this:
{
"Cat": {
"type": "object",
"properties": {
"pet_type": {
"type": "string"
},
"hunts": {
"type": "boolean"
},
"age": {
"type": "integer"
}
},
"discriminator": {
"propertyName": "pet_type"
}
}
}
And the test2.json like this:
{
"Dog": {
"type": "object",
"properties": {
"pet_type": {
"type": "string"
},
"bark": {
"type": "boolean"
},
"breed": {
"type": "string",
"enum": [
"Dingo",
"Husky",
"Retriever",
"Shepherd"
]
}
},
"discriminator": {
"propertyName": "pet_type"
}
}
}
The desired out come would be to toggle between the two "test" jsons based on an enum (the drop down seen in the reDoc sample). What am I missing to get this result?
You can see an example of the discriminator result here under the feature section (the first gif)
After more digging I was able to figure out the issue... my structure for the most part.
On my index.json file I updated my components section to point at my components folder containing the schema as such:
"components": {
"$ref": "./components/test.json"
},
The test.json looks like the following:
{
"schemas": {
"Refinance": {
"description": "A representation of a cat",
"allOf": [
{
"$ref": "#/schemas/Pet"
},
{
"type": "object",
"properties": {
"huntingSkill": {
"type": "string",
"description": "The measured skill for hunting",
"default": "lazy",
"enum": [
"clueless",
"lazy",
"adventurous",
"aggressive"
]
}
},
"required": [
"huntingSkill"
]
}
]
},
"Purchase": {
"description": "A representation of a dog",
"allOf": [
{
"$ref": "#/schemas/Pet"
},
{
"type": "object",
"properties": {
"packSize": {
"type": "integer",
"format": "int32",
"description": "The size of the pack the dog is from",
"default": 1,
"minimum": 1
},
"foobar": {
"type": "string",
"description": "some ol bullshit"
}
},
"required": [
"packSize"
]
}
]
},
"Pet": {
"type": "object",
"discriminator": {
"propertyName": "petType"
},
"properties": {
"petType": {
"description": "Type of a pet",
"type": "string"
}
},
"xml": {
"name": "Pet"
}
}
}
}
And finally the schema for the endpoint gets referenced as follows:
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../../index.json#/components/schemas/Pet"
}
}
}
},

Powerapps difficulty accessing JSON in collection

I'm having difficulty accessing data in a collection, via PowerApps.
I create the collection with this:
Collect(coll15,mt.GetAnswers("3b....da","application/json",{question:"eco"}))
Using Developer Tools -> Network tab -> Response body - the following JSON data is returned:
{
"answers": [
{
"answer": "This is the answer",
"questions": [
"Private vehicle eco renewal"
],
"score": 82.901087775826454
}
]
}
The collection is created.
I then add a gallery control to my page - however the only options I have to bind to the labels are: ThisItem.Value
If I try to enter ThisItem.Value.answer I get the error: Invalid use of '.'
If I enter ThisItem.answers.answer I get the error: Invalid name
This is the swagger file:
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "mt",
"description": "mt"
},
"host": "westus.api.cognitive.microsoft.com:443",
"basePath": "/",
"schemes": [
"https"
],
"consumes": [],
"produces": [
"application/json"
],
"paths": {
"/qnamaker/v2.0/knowledgebases/eeeee.....eeeee/generateAnswer": {
"post": {
"summary": "GetAnswers",
"description": "Get answers from qna",
"operationId": "GetAnswers",
"parameters": [
{
"name": "body",
"in": "body",
"schema": {
"type": "object",
"properties": {
"question": {
"type": "string",
"description": "question",
"x-ms-summary": "question",
"title": "question",
"x-ms-visibility": ""
}
},
"default": {
"question": "hi"
},
"required": [
"question"
]
},
"required": true
}
],
"responses": {
"default": {
"description": "default",
"schema": {
"type": "string"
}
}
}
}
}
},
"definitions": {},
"parameters": {},
"responses": {},
"securityDefinitions": {
"api_key": {
"type": "apiKey",
"in": "header",
"name": "Ocp-Apim-Subscription-Key"
}
},
"security": [
{
"oauth2_auth": [
"Offline-Access"
]
}
],
"tags": []
}
Is there any way for me to access the answer text within the collection?
Thanks for any help,
Mark
The problem is that the response type for the operation in the connector definition is string:
"responses": {
"default": {
"description": "default",
"schema": {
"type": "string"
}
}
}
But your response is an object instead. If you update your custom connector to use a typed object instead, you should be able to access the response from the operation. Something along the lines of the schema below:
"responses": {
"default": {
"description": "default",
"schema": {
"type": "object",
"properties": {
"answers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"answer": {
"type": "string"
},
"questions": {
"type": "array",
"items": {
"type": "string"
}
},
"score": {
"type": "number",
"format": "float"
}
}
}
}
}
}
}
},
Notice that in the portal (web.powerapps.com), if you go to your custom connector definition, and select "Edit", you can go to the operation, and select the response you want to edit:
And then use the "Import from sample" option
With that, if you enter an example of a response from the API, it will create the schema for you (which is similar to the one I have above).

Swagger-UI Maximum call stack size exceeded -> Backreference

When calling my swagger.json from the swagger-ui I get an error:
Maximum call stack size exceeded
I guess it is because I have
Token which has an owner of Type User
User which has a Token of Type Token
When using the online-version of the swagger editior it can resolve the types. How can I configure swagger to resolve the types correctly?
The full swagger.json
{
"swagger": "2.0",
"info": {
"description": "Descr",
"version": "1.0.0",
"title": "Skeleton"
},
"host": "1.1.1.1:11",
"basePath": "/api",
"tags": [{
"name": "auth"
}
],
"schemes": ["http"],
"paths": {
"/auth/local": {
"post": {
"tags": ["auth"],
"summary": "Authenticates User",
"description": "This auths only local users",
"operationId": "authenticateUser",
"consumes": ["application/json"],
"produces": ["application/json"],
"parameters": [{
"in": "body",
"name": "body",
"required": false,
"schema": {
"$ref": "#/definitions/Credentials"
}
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/AuthResponse"
}
}
}
}
},
"/auth/ldap": {
"post": {
"tags": ["auth"],
"operationId": "authenticateLdapUser",
"produces": ["application/json"],
"parameters": [{
"in": "body",
"name": "body",
"required": false,
"schema": {
"$ref": "#/definitions/Credentials"
}
}
],
"responses": {
"default": {
"description": "successful operation"
}
}
}
}
},
"definitions": {
"AuthResponse": {
"type": "object",
"properties": {
"issued": {
"type": "string",
"format": "date-time"
},
"responseType": {
"type": "string",
"enum": ["RESPONSE", "ERROR", "UNAUTHORIZED", "OK"]
},
"responseDescription": {
"type": "string"
},
"accessToken": {
"$ref": "#/definitions/Token"
},
"resourceName": {
"type": "string"
}
}
},
"Note": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"content": {
"type": "string"
},
"modified": {
"type": "string",
"format": "date-time"
}
}
},
"Token": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"expirationDate": {
"type": "string",
"format": "date-time"
},
"issued": {
"type": "string",
"format": "date-time"
},
"expired": {
"type": "boolean"
},
"owner": {
"$ref": "#/definitions/User"
}
}
},
"User": {
"type": "object",
"properties": {
"username": {
"type": "string"
},
"password": {
"type": "string"
},
"email": {
"type": "string"
},
"displayName": {
"type": "string"
},
"notes": {
"type": "array",
"items": {
"$ref": "#/definitions/Note"
}
},
"accessToken": {
"$ref": "#/definitions/Token"
}
}
},
"Credentials": {
"type": "object",
"properties": {
"user": {
"type": "string"
},
"password": {
"type": "string"
}
}
}
}
}
I have the same problem and I removed format: date-time and the error is gone.
Still I don't know what causes the error. But without that format everything goes ok.
In FastAPI which uses Swagger UI, I was receiving the same error. I updated the FastAPI package to get the last version of Swagger UI and then set the value of 'syntaxHighlight' to False, like below:
app = FastAPI(swagger_ui_parameters={'syntaxHighlight': False})
Just search how you can set this param directly in Swagger UI. This may fix your issue.

Load HTML into Swagger Docs Implementation Notes

I'm attempting to display HTML for my implementation notes for a given endpoint using Swagger Docs. Below, I've typed out the HTML as a string, but I love to load these in as a module of some sort, so that I can simply edit HTML files separately.
I couldn't find an answer in the Google Group and I'd like to see if this is something that is already solved before I create some sort of grunt plug-in to handle it.
Here's my current code:
module.exports = function (swagger) {
var docs = swagger.createResource("/docs/endpoint");
docs.get('/endpoint', "Endpoint Title", {
"summary": "Some description about the endpoint",
"notes": " \
<h2>Getting Started with Endpoint:</h2> \
<br /><p>This endpoint some some really important things.</p> \
",
"type": "",
"nickname": "",
"parameters": [
{
"name": "apiKey",
"description": "The API Key for the requesting application",
"required": true,
"type": "string",
"paramType":"query"
}]
[...]
Is there a cleaner way to implement this?
Swagger 2.0 adds some more flexibility with rich documentation.
One way, is the ability to add markdown tags (GFM flavor) to the description fields.
Another way, is to use the externalDocs property where applicable to add an external documentation resource. An example for it would be:
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
"termsOfService": "http://helloreverb.com/terms/",
"contact": {
"name": "Wordnik API Team",
"email": "foo#example.com",
"url": "http://madskristensen.net"
},
"license": {
"name": "MIT",
"url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
}
},
"externalDocs": {
"description": "find more info here",
"url": "https://helloreverb.com/about"
},
"host": "petstore.swagger.wordnik.com",
"basePath": "/api",
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/pets": {
"get": {
"description": "Returns all pets from the system that the user has access to",
"operationId": "findPets",
"externalDocs": {
"description": "find more info here",
"url": "https://helloreverb.com/about"
},
"produces": [
"application/json",
"application/xml",
"text/xml",
"text/html"
],
"parameters": [
{
"name": "tags",
"in": "query",
"description": "tags to filter by",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "csv"
},
{
"name": "limit",
"in": "query",
"description": "maximum number of results to return",
"required": false,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/pet"
}
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/errorModel"
}
}
}
},
"post": {
"description": "Creates a new pet in the store. Duplicates are allowed",
"operationId": "addPet",
"produces": [
"application/json"
],
"parameters": [
{
"name": "pet",
"in": "body",
"description": "Pet to add to the store",
"required": true,
"schema": {
"$ref": "#/definitions/newPet"
}
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "#/definitions/pet"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/errorModel"
}
}
}
}
},
"/pets/{id}": {
"get": {
"description": "Returns a user based on a single ID, if the user does not have access to the pet",
"operationId": "findPetById",
"produces": [
"application/json",
"application/xml",
"text/xml",
"text/html"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to fetch",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "#/definitions/pet"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/errorModel"
}
}
}
},
"delete": {
"description": "deletes a single pet based on the ID supplied",
"operationId": "deletePet",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"204": {
"description": "pet deleted"
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/errorModel"
}
}
}
}
}
},
"definitions": {
"pet": {
"required": [
"id",
"name"
],
"externalDocs": {
"description": "find more info here",
"url": "https://helloreverb.com/about"
},
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"newPet": {
"allOf": [
{
"$ref": "pet"
},
{
"required": [
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
}
}
}
]
},
"errorModel": {
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}
}
}

Resources