In my "simplified" API, all responses are derived (inherit) from a base "response" class. The response class is composed of a header filled with metadata, and the body which contains the core data the the user is requesting. The response (in JSON) is laid out such that all the metadata is on the first "layer" and the body is a single attribute called "body" as such
response |--metadata attribute 1 (string/int/object) |--metadata attribute 2 (string/int/object) |--body (object) |--body attribute 1 (string/int/object) |--body attribute 2 (string/int/object)
I have tried to define this relationship in swagger with the following JSON:
{ ... "definitions": { "response": { "allOf": [ { "$ref": "#/definitions/response_header" }, { "properties": { "body": { "description": "The body of the response (not metadata)", "schema": { "$ref": "#/definitions/response_body" } } } } ] }, "response_header": { "type": "object", "required": [ "result" ], "properties": { "result": { "type": "string", "description": "value of 'success', for a successful response, or 'error' if there is an error", "enum": [ "error", "success" ] }, "message": { "type": "string", "description": "A suitable error message if something went wrong." } } }, "response_body": { "type": "object" } } }
I then try to create different responses by creating the various body/header classes that inherit from body/header, and then create child response classes that are composed of the relevant header/body classes (shown in source code at bottom). However, I am certain that either this is the wrong way to do things, or that my implementation is incorrect. I have been unable to find an example of inheritance in the swagger 2.0 specification (shown below) but have found an example of composition.
I am pretty certain that this "discriminator" has a large part to play, but not sure what I need to do.
Could someone show me how one is supposed to implement composition+inheritance in swagger 2.0 (JSON), preferably by "fixing" my example code below. It would also be great if I could specify an ErrorResponse class that inherits from response where the "result" attribute in the header is always set to "error".
{ "swagger": "2.0", "info": { "title": "Test API", "description": "Request data from the system.", "version": "1.0.0" }, "host": "xxx.xxx.com", "schemes": [ "https" ], "basePath": "/", "produces": [ "application/json" ], "paths": { "/request_filename": { "post": { "summary": "Request Filename", "description": "Generates an appropriate filename for a given data request.", "responses": { "200": { "description": "A JSON response with the generated filename", "schema": { "$ref": "#/definitions/filename_response" } } } } } }, "definitions": { "response": { "allOf": [ { "$ref": "#/definitions/response_header" }, { "properties": { "body": { "description": "The body of the response (not metadata)", "schema": { "$ref": "#/definitions/response_body" } } } } ] }, "response_header": { "type": "object", "required": [ "result" ], "properties": { "result": { "type": "string", "description": "value of 'success', for a successful response, or 'error' if there is an error", "enum": [ "error", "success" ] }, "message": { "type": "string", "description": "A suitable error message if something went wrong." } } }, "response_body": { "type": "object" }, "filename_response": { "extends": "response", "allOf": [ { "$ref": "#definitions/response_header" }, { "properties": { "body": { "schema": { "$ref": "#definitions/filename_response_body" } } } } ] }, "filename_response_body": { "extends": "#/definitions/response_body", "properties": { "filename": { "type": "string", "description": "The automatically generated filename" } } } } }
To try and clarify what I want, I have created the very basic diagram below which aims to show that all responses are instantiations of the "response" object that have been built by (composition) using any combination of response_header and response_body objects. The response_header and response_body objects can be extended and inserted into any response object, which is done in the case of a filename_response which uses the filename_response_body child of the base response_body class. Both error and successful responses use the "response" object.
Use the anyOf keyword to validate the data against any amount of the given subschemas. That is, the data may be valid against one or more subschemas at the same time.
Basic authentication. API key (as a header or query parameter) OAuth 2 common flows (implicit, password, application and access code)
OpenAPI 3.0 data types are based on an extended subset JSON Schema Specification Wright Draft 00 (aka Draft 5). The data types are described using a Schema object. To learn how to model various data types, see the following topics: Data Types.
The discriminator is the schema property name that is used to differentiate between other schema that inherit this schema. The property name used MUST be defined at this schema and it MUST be in the required property list. When used, the value MUST be the name of this schema or any schema that inherits it.
As a beginner in swagger I don't find the official documentation about polimorphism and composition easy to undestand, because it lacks an example. When I searched the net, there are lots of good examples refering to swagger 1.2 when extends
was valid.
For swagger 2.0 I found a good example in swagger spec sources on github via this google group
Based on above sources, here is a short valid inheritance example in YAML:
definitions: Pet: discriminator: petType required: - name - petType # required for inheritance to work properties: name: type: string petType: type: string Cat: allOf: - $ref: '#/definitions/Pet' # Cat has all properties of a Pet - properties: # extra properties only for cats huntingSkill: type: string default: lazy enum: - lazy - aggressive Dog: allOf: - $ref: '#/definitions/Pet' # Dog has all properties of a Pet - properties: # extra properties only for dogs packSize: description: The size of the pack the dog is from type: integer
I've found that composition works fine even without definition of discriminator
.
For example, base Response
:
definitions: Response: description: Default API response properties: status: description: Response status `success` or `error` type: string enum: ["success", "error"] error_details: description: Exception message if called type: ["string", "object", "null"] error_message: description: Human readable error message type: ["string", "null"] result: description: Result body type: ["object", "null"] timestamp: description: UTC timestamp in ISO 8601 format type: string required: - status - timestamp - error_details - error_message - result
Is rendered as:
And we can extend it to refine custom schema of result
field:
FooServiceResponse: description: Response for Foo service allOf: - $ref: '#/definitions/Response' - properties: result: type: object properties: foo_field: type: integer format: int32 bar_field: type: string required: - result
And it will be correctly rendered as:
Note, that allOf
is enough for this to work and no discriminator
field is used. This is good, because it works and this is important, as I think, tools will be able to generate code without discriminator
field.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With