Dans mon API "simplifiée", toutes les réponses sont dérivées ( héritées ) d'une classe "réponse" de base. La classe de réponse est composée d'un en-tête rempli de métadonnées et du corps contenant les données de base demandées par l'utilisateur. La réponse (en JSON) est disposée de telle sorte que toutes les métadonnées se trouvent sur le premier "calque" et que le corps est un attribut unique appelé "corps" en tant que tel.
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)
J'ai essayé de définir cette relation en swagger avec le JSON suivant:
{
...
"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"
}
}
}
J'essaie ensuite de créer différentes réponses en créant les différentes classes de corps/en-tête héritées du corps/en-tête, puis de créer des classes de réponses enfants composées des classes d'en-tête/de corps pertinentes (indiquées dans le code source en bas). Cependant, je suis certain que ce n'est pas la bonne façon de faire les choses ou que ma mise en œuvre est incorrecte. J'ai été incapable de trouver un exemple d'héritage dans spécification swagger 2. (ci-dessous), mais j'ai trouvé un exemple de composition .
Je suis à peu près certain que ce "discriminateur" a un rôle important à jouer, mais je ne suis pas sûr de ce que je dois faire.
Est-ce que quelqu'un pourrait me montrer comment on est supposé implémenter composition + héritage dans swagger 2.0 (JSON), de préférence en "corrigeant" mon exemple de code ci-dessous. Ce serait également bien si je pouvais spécifier une classe ErrorResponse qui hérite de la réponse où l'attribut "result" dans l'en-tête est toujours défini sur "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"
}
}
}
}
}
Pour essayer de clarifier ce que je veux, j'ai créé le diagramme très basique ci-dessous qui vise à montrer que toutes les réponses sont des instanciations de l'objet "réponse" construit par (composition) en utilisant une combinaison quelconque des objets response_header et response_body. Les objets response_header et response_body peuvent être étendus et insérés dans n'importe quel objet de réponse, ce qui est fait dans le cas d'un filename_response qui utilise l'enfant filename_response_body de la classe de base de response_body. Les réponses d'erreur et de succès utilisent l'objet "réponse".
En tant que débutant, je ne trouve pas le documentation officielle sur le polimorphisme et la composition facile à comprendre, car il manque d’exemple Quand j'ai cherché sur le net, il y a beaucoup de bons exemples faisant référence à swagger 1.2 lorsque extends
était valide.
Pour swagger 2.0 , j'ai trouvé un bon exemple dans sources swagger spec sur github via this google group
Sur la base des sources ci-dessus, voici un court exemple d'héritage valide en 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
J'ai trouvé que la composition fonctionne bien même sans définition de discriminator
.
Par exemple, 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
Est rendu comme:
Et nous pouvons l’étendre pour affiner le schéma personnalisé du champ result
:
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
Et il sera correctement rendu comme:
Notez que allOf
suffit pour que cela fonctionne et aucun champ discriminator
n’est utilisé. C’est bien, car cela fonctionne et c’est important, car je pense que les outils seront capables de générer du code sans le champ discriminator
.
Toutes les réponses ici sont déjà excellentes, mais je veux juste ajouter une note mineure à propos de composition versus héritage . Selon la Swagger/OpenAPI Spec , pour mettre en œuvre une composition , utiliser la propriété allOf
suffit, car @ oblalex souligne correctement . Cependant, pour implémenter l'héritage , vous devez utiliser allOf
avec discriminator
, comme dans l'exemple par @ TomaszSętkowski .
De plus, j'ai trouvé d'autres exemples Swagger de composition et héritage chez API Handyman. Ils font partie d'un excellente série de tutoriels Swagger/OpenAPI par Arnaud Lauret que je pense que tout le monde devrait vérifier.
L'exemple standard Swagger 2.0 que vous avez partagé décrit une relation de composition, plus précisément, il capture une relation "est une sorte de" super-type/sous-type, mais il ne s'agit pas d'un polymorphisme en soi.
Ce serait le cas si vous pouviez référencer la définition de base de Pet en tant que paramètre d'entrée, puis choisir Cat ou entrer un objet JSON Cat comme valeur pour la demande d'entrée et le faire pour Swagger UI.
Je ne pouvais pas obtenir que cela fonctionne directement.
Le mieux que je pouvais obtenir était de définir additionalProperties sur true sur l'objet de base (par exemple, Pet), de spécifier Pet en utilisant la référence de pointeur JSON comme schéma d'entrée et enfin de copier-coller mon objet de valeur Cat JSON dans l'interface utilisateur Swagger. Puisque les propriétés supplémentaires sont autorisées, l’interface utilisateur de Swagger a généré une charge utile de demande d’entrée valide.