OpenAPI-Specification
OpenAPI-Specification copied to clipboard
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.
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"
]
}
}
}
If I understand right, you want support for generic data types. Apart from simple maps (with string keys, being represented as JSON objects) or lists (being represented as JSON arrays), OpenAPI doesn't support that yet.
A related issue I found is #519.
@ePaul , yes sort of. 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). The composition concept in Swagger (example 1 above) works great when I run it through swagger2markup and renders the content as I would hope/expect. SwaggerUI represents it as multiple objects and some nesting as a part of it too, so it's rather odd and confusing. This leaves me questioning if it's an issue with SwaggerUI, my Swagger structure, or something else. So trying to figure out the best way to represent the scenario in Swagger.
Markup rendered:

Swagger UI rendered:

Swagger UI rendered - expanded:

will this to be supported in future?
I am evaluating this as a possible use case for overlays, https://github.com/OAI/Overlay-Specification/discussions/9.
I don't think overlays are needed here. I believe this can be represented in openapi3 as example (I did not test this)
{
"openapi": "3.0.1",
"info": {
"title": "API",
"version": "1.0"
},
"paths": {
"/permissions": {
"get": {
"description": "Returns all permissions",
"operationId": "getPermissions",
"responses": {
"200": {
"description": "success",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/permissionResponse"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"permissionResponse": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "A string indicating the response from the server."
},
"totalElements": {
"type": "integer",
"description": "The number of items retrieved.",
"format": "int64"
},
"status": {
"type": "string",
"description": "A string indicating the response from the server."
},
"data": {
"type": "array",
"description": "The collection of items returned from the API request.",
"items": {
"oneOf": [
{
"$ref": "#/components/schemas/permission",
},
{
"$ref": "#/components/schemas/role"
}
]
}
}
}
},
"role": {
"type": "object",
"properties": {
"roleName": {
"type": "string"
},
"description": {
"type": "string"
}
}
},
"permission": {
"required": [
"active",
"description",
"id",
"label"
],
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "Unique identifier representing a specific permission.",
"format": "int64"
},
"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."
}
}
}
}
}
}
which looks like this at editor.swagger.io

This has been supported in OAS 3.1 by using dynamic references to implement generic types.