Object array rendered as empty array in Swagger UI - swagger

I have the following model definitions in an OpenAPI/Swagger spec:
"definitions": {
"models.Equipment": {
"title": "Equipment",
"type": "object",
"properties": {
"Features": {
"type": "array",
"items": {
"$ref": "#/definitions/models.Feature"
}
},
"Id": {
"type": "integer",
"format": "int64"
},
"IdType": {
"type": "string"
},
"Name": {
"type": "string"
},
"Price": {
"type": "integer",
"format": "int32"
}
}
},
"models.Feature": {
"title": "Feature",
"type": "object",
"properties": {
"Equipments": {
"type": "array",
"items": {
"$ref": "#/definitions/models.Equipment"
}
},
"Id": {
"type": "integer",
"format": "int64"
},
"IdFeature": {
"$ref": "#/definitions/models.Feature"
},
"Name": {
"type": "string"
}
}
}
}
In the Feature model, he Equipments property is defined as an array of Equipment models, but Swagger UI 3.x renders it as an empty array []. Everywhere Feature model is used, like as examples for POST method in Feature I have this kind of display.
Is the definition incorrect in some way?
The complete spec is here:
https://dl.dropboxusercontent.com/s/anjfhgxhr0pfmnu/swagger-bug.json

This seems to be a bug in Swagger UI and is most likely caused by circular references in your models - models.Equipment references models.Feature, and models.Feature references models.Equipment. You can open an issue in the Swagger UI repository on GitHub.
Your spec also contains errors in the response definitions:
"responses": {
"200": {
"schema": {
"$ref": "#/definitions/models.Equipment"
}
},
"403": {}
}
Each response must have a description, so the correct version would be:
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/models.Equipment"
}
},
"403": {
"description": "Oops"
}
}

Related

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"
}
}
}
},

Swagger/Swashbuckle showing "Unknown response type"

I am creating an C# ASP.NET Core 2.0 REST API, all going well for the most part. It is using MVC routing to gen the REST API. The controllers are pretty simple.
// POST: api/Volume/{zoneID}/Set/{volume}
[HttpPost("{zoneId:int}/[action]/{volume:int}", Name = "Set")]
public IActionResult Set(int zoneId, int volume)
{
return CreateAndSend(strZonesLevel, zoneId, $"{volume:X2}");
}
Using the latest of everything, installed Swagger/Swashbuckle for AspNetCore 2.3.0 and the UI comes up with the APIs and all. The SwashBuckle UI works well, I can test the API etc.
The one exception is that on the UI, the Response type ALWAYS comes back as "Unknown Response Type."
https://i.stack.imgur.com/6qqBh.jpg
I have the following attributes in front of my class (all methods return the same type)
[Produces("application/json")]
[Route("api/Volume")]
[ProducesResponseType(typeof(ControllerResponseModel), 200)]
[ProducesResponseType(typeof(ControllerResponseModel), 400)]
[ProducesResponseType(typeof(ControllerResponseModel), 500)]
The generated JSON seems allright, the ControllerResponseModel is in the definition, and referenced in all the right places by the Volume API. Here is a subset.
{
"swagger": "2.0",
"info": {
"version": "v1",
"title": "AVController API"
},
"paths": {
"/api/Volume/{zoneId}/Set/{volume}": {
"post": {
"tags": ["Volume"],
"operationId": "ApiVolumeByZoneIdSetByVolumePost",
"consumes": [],
"produces": ["application/json"],
"parameters": [
{
"name": "zoneId",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
},
{
"name": "volume",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "Success",
"schema": {
"type": "array",
"items": { "$ref": "#/definitions/ControllerResponseModel" }
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "array",
"items": { "$ref": "#/definitions/ControllerResponseModel" }
}
},
"500": {
"description": "Server Error",
"schema": {
"type": "array",
"items": { "$ref": "#/definitions/ControllerResponseModel" }
}
}
}
}
}
},
"definitions": {
"ControllerResponseModel": {
"type": "object",
"properties": {
"command": { "type": "string" },
"message": { "type": "string" },
"url": { "type": "string" }
}
}
}
}
Any ideas why the UI would not be showing the return type and value? I have tried numerous things, like using gets instead of posts as well as using the [SwaggerResponse] attributes, but the results are the same.
This has been identified as an Edge browser issue with Swashbuckle, not the code posted here. It is reproducible on many sites. Issue has posted on GitHub # https://github.com/swagger-api/swagger-ui/issues/4337

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.

Swagger: Common response/payload object but different data defined per API?

What is the best way to represent a generic response/payload object that has basic fields such as message, total elements, data, and status? Where the variability between each API is the data element. For instance, one API could be for permissions, so the data element would hold an array of permissions. But for another API, it would hold a different array of object types. My main goal is to have reuse with a payload object and to define the next "layer" of actual data.
I want to be able to define a data type that's generic - like a "response" that has basic fields but I want to be able to further define that content for each API (data containing permissions or roles or whatever).
Here are some JSON samples of what's been attempted but isn't rendering the way we would expect it to in Swagger UI (i.e. a flat structure of 4 elements with data defined per the API).
Example 1 - composition:
{
"swagger": "2.0",
"host": "localhost:8888",
"info": {
"version": "0.0.1",
"title": "API"
},
"paths": {
"/permissions": {
"get": {
"description": "Returns all permissions",
"operationId": "getPermissions",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "success",
"schema": {
"$ref": "#/definitions/permissionResponse"
}
}
}
}
}
},
"definitions": {
"response": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "A string indicating the response from the server."
},
"totalElements": {
"type": "integer",
"format": "int64",
"description": "The number of items retrieved."
},
"status": {
"type": "string",
"description": "A string indicating the response from the server."
}
}
},
"permissionResponse": {
"allOf": [
{
"$ref": "#/definitions/response"
}, {
"type": "object",
"properties": {
"data": {
"type": "array",
"description": "The collection of items returned from the API request.",
"items": {
"$ref": "#/definitions/permission"
}
}
}
}
]
},
"permission": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": "Unique identifier representing a specific permission."
},
"label": {
"type": "string",
"description": "The label of a permission."
},
"description": {
"type": "string",
"description": "A description of the permission."
},
"active": {
"type": "boolean",
"description": "A flag indicating whether a permission is active."
}
},
"required": [
"id",
"label",
"description",
"active"
]
}
}
}
Example 2 - composition variation:
{
"swagger": "2.0",
"host": "localhost:8888",
"info": {
"version": "0.0.1",
"title": "API"
},
"paths": {
"/permissions": {
"get": {
"description": "Returns all permissions",
"operationId": "getPermissions",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "success",
"schema": {
"$ref": "#/definitions/permissionResponse"
}
}
}
}
}
},
"definitions": {
"response": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "A string indicating the response from the server."
},
"totalElements": {
"type": "integer",
"format": "int64",
"description": "The number of items retrieved."
},
"status": {
"type": "string",
"description": "A string indicating the response from the server."
}
}
},
"permissionResponse": {
"allOf": [
{
"$ref": "#/definitions/response"
}],
"type": "object",
"properties": {
"data": {
"type": "array",
"description": "The collection of items returned from the API request.",
"items": {
"$ref": "#/definitions/permission"
}
}
}
},
"permission": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": "Unique identifier representing a specific permission."
},
"label": {
"type": "string",
"description": "The label of a permission."
},
"description": {
"type": "string",
"description": "A description of the permission."
},
"active": {
"type": "boolean",
"description": "A flag indicating whether a permission is active."
}
},
"required": [
"id",
"label",
"description",
"active"
]
}
}
Example 3 - additional properties:
{
"swagger": "2.0",
"host": "localhost:8888",
"info": {
"version": "0.0.1",
"title": "API"
},
"paths": {
"/permissions": {
"get": {
"description": "Returns all permissions",
"operationId": "getPermissions",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "success",
"schema": {
"$ref": "#/definitions/permissionResponse"
}
}
}
}
}
},
"definitions": {
"response": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "A string indicating the response from the server."
},
"totalElements": {
"type": "integer",
"format": "int64",
"description": "The number of items retrieved."
},
"status": {
"type": "string",
"description": "A string indicating the response from the server."
}
}
},
"permissionResponse": {
"type": "object",
"properties": {
"data": {
"type": "array",
"description": "The collection of items returned from the API request.",
"items": {
"$ref": "#/definitions/permission"
}
}
},
"additionalProperties": {
"$ref": "#/definitions/response"
}
},
"permission": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"description": "Unique identifier representing a specific permission."
},
"label": {
"type": "string",
"description": "The label of a permission."
},
"description": {
"type": "string",
"description": "A description of the permission."
},
"active": {
"type": "boolean",
"description": "A flag indicating whether a permission is active."
}
},
"required": [
"id",
"label",
"description",
"active"
]
}
}
Example 1 renders well with swagger2markup showing the consolidated view of the data with the other 3 elements and having a permission array. However, with Swagger UI, it renders it differently, separating the objects out.
Markup rendered:
Swagger UI rendered
Swagger UI rendered - expanded

ElasticSearch: Indexing with multiple mapping types

I am trying to fully comprehend indexing with multiple mapping types in ElasticSearch. In the docs it gives example code:
PUT my_index
{
"mappings": {
"user": {
"_all": { "enabled": false },
"properties": {
"title": { "type": "string" },
"name": { "type": "string" },
"age": { "type": "integer" }
}
},
"blogpost": {
"properties": {
"title": { "type": "string" },
"body": { "type": "string" },
"user_id": {
"type": "string",
"index": "not_analyzed"
},
"created": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
}
}
}
}
}
With this mapping how would I then create and search on an object?
For create would it be:
POST my_index/user/blogspot
or
POST my_index/user,blogspot
For searching would it be:
GET my_index/user/blogspot
or
GET my_index/user,blogspot
or something else?
An example of a POST and GET with multiple mapping would really help me out. Thank you so much!

Resources