W moim „uproszczonym” interfejsie API wszystkie odpowiedzi są wyprowadzane ( dziedziczone ) z podstawowej klasy „odpowiedzi”. Klasa odpowiedzi składa się z nagłówka wypełnionego metadanymi oraz treści zawierającej podstawowe dane, o które prosi użytkownik. Odpowiedź (w formacie JSON) jest ułożona w taki sposób, że wszystkie metadane znajdują się na pierwszej „warstwie”, a treść jest pojedynczym atrybutem o nazwie „body”.
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)
Próbowałem zdefiniować tę relację z zachwytem za pomocą następującego kodu 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"
}
}
}
Następnie próbuję utworzyć różne odpowiedzi, tworząc różne klasy treści / nagłówka, które dziedziczą po treści / nagłówku, a następnie tworzę klasy odpowiedzi potomnych, które składają się z odpowiednich klas nagłówka / treści (pokazane w kodzie źródłowym na dole). Jestem jednak pewien, że albo jest to niewłaściwy sposób robienia rzeczy, albo że moja implementacja jest nieprawidłowa. Nie udało mi się znaleźć przykładu dziedziczenia w specyfikacji Swagger 2.0 (pokazanej poniżej), ale znalazłem przykład kompozycji .
Jestem prawie pewien, że ten „dyskryminator” ma dużą rolę do odegrania, ale nie wiem, co powinienem zrobić.
Pytanie
Czy ktoś mógłby mi pokazać, jak należy zaimplementować kompozycję + dziedziczenie w swagger 2.0 (JSON), najlepiej "naprawiając" mój przykładowy kod poniżej. Byłoby również świetnie, gdybym mógł określić klasę ErrorResponse, która dziedziczy z odpowiedzi, w której atrybut „result” w nagłówku jest zawsze ustawiony na „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"
}
}
}
}
}
Aktualizacja diagramu
Aby spróbować wyjaśnić, czego chcę, utworzyłem poniżej bardzo podstawowy diagram, który ma na celu pokazanie, że wszystkie odpowiedzi są instancjami obiektu „response”, który został zbudowany przez (kompozycja) przy użyciu dowolnej kombinacji obiektów response_header i response_body. Obiekty response_header i response_body mogą być rozszerzone i wstawione do dowolnego obiektu odpowiedzi, co ma miejsce w przypadku pliku nazwa_odpowiedzi, która używa elementu potomnego filename_response_body z podstawowej klasy response_body. Zarówno błędy, jak i pomyślne odpowiedzi używają obiektu „odpowiedź”.
I have the properties of X and my own properties.
. Dziedziczenie sugeruje związekX is my parent. I have its properties and my own.
. Dziedziczenie jest przydatne, jeśli chcesz powiedzieć, że używany jest określony zestaw modeli, w których rodzic jest używany.Odpowiedzi:
Jako początkujący zuchwale nie uważam oficjalnej dokumentacji dotyczącej polimorfizmu i kompozycji za łatwą do zrozumienia, bo brakuje w niej przykładu . Kiedy przeszukiwałem sieć, jest wiele dobrych przykładów odnoszących się do Swagger 1.2, kiedy
extends
był ważny.Dla swaggera 2.0 znalazłem dobry przykład w źródłach specyfikacji na github za pośrednictwem tej grupy google
Na podstawie powyższych źródeł, oto krótki prawidłowy przykład dziedziczenia w YAML:
źródło
editor.swagger.io
widzę mały błąd: w sekcji modeli widzęPet
model wiele razy. Zawartość tych modeli jest w porządku. Tylko nazwy są błędne.editor2.swagger.io
nie zobaczysz tego problemuPet
, a jeśli klasa A rozszerza klasę B, czy też powinniśmy go używać? DziękujęOdkryłem, że kompozycja działa dobrze nawet bez definicji
discriminator
.Na przykład podstawa
Response
:Jest renderowany jako:
I możemy go rozszerzyć, aby udoskonalić niestandardowy schemat
result
pola:I zostanie poprawnie wyrenderowany jako:
Zauważ, że
allOf
to wystarczy, aby to zadziałało i żadnediscriminator
pole nie jest używane. To dobrze, bo działa i to jest ważne, bo myślę, że narzędzia będą w stanie wygenerować kod bezdiscriminator
pól.źródło
allOf
, ale w jakiś sposóbopenapi.yaml
stwierdzam, że podklasy zawierają właściwości superklasy w sposób nadmiarowy, czy to prawda?Wszystkie odpowiedzi tutaj są już doskonałe, ale chcę tylko dodać drobną uwagę na temat kompozycji w porównaniu z dziedziczeniem . Zgodnie ze specyfikacją Swagger / OpenAPI , aby zaimplementować kompozycję ,
allOf
wystarczy użyć właściwości, jak słusznie wskazuje @oblalex . Jednak aby zaimplementować dziedziczenie , trzeba skorzystaćallOf
zdiscriminator
, jak w przykładzie @ TomaszSętkowski .Znalazłem także więcej przykładów Swagger zarówno kompozycji, jak i dziedziczenia w API Handyman. Są częścią doskonałej serii tutoriali Swagger / OpenAPI autorstwa Arnauda Laureta, którą myślę, że każdy powinien sprawdzić.
źródło
Standardowy przykład Swagger 2.0, który udostępniłeś, przedstawia relację kompozycji, a konkretnie przedstawia „to rodzaj” relacji nadtyp / podtyp, ale nie jest to polimorfizm sam w sobie.
Byłoby tak, gdybyś mógł odwołać się do podstawowej definicji Pet jako parametru wejściowego, a następnie wybrać Cat lub wprowadzić obiekt Cat JSON jako wartość dla żądania wejściowego i mieć to akceptowalne dla interfejsu Swagger UI.
Nie mogłem zmusić tego do bezpośredniego działania.
Najlepsze, co mogłem uzyskać, to ustawić dodatkowe właściwości na true w obiekcie podstawowym (np. Pet), określić Pet za pomocą odniesienia wskaźnika JSON jako schematu wejściowego, a na koniec skopiować i wkleić mój obiekt wartości Cat JSON do interfejsu użytkownika Swagger. Ponieważ dodatkowe właściwości są dozwolone, interfejs użytkownika Swagger wygenerował prawidłowy ładunek żądania wejściowego.
źródło