In Teil 1 dieser Serie (https://liferay.dev/blogs/-/blogs/creating-headless-apis-part-1) verwenden Sie die REST Builder-Tools von Liferay, um Ihre eigene benutzerdefinierte kopflose API zu erstellen. Wir haben ein Projekt gestartet, um es zu bauen. Wir haben das Projekt gestartet und vier Module erstellt, um Sie in die Abschnitte Meta und wiederverwendbare Komponenten der OpenAPI Yaml-Datei einzuführen.
In diesem Artikel, der eine Fortsetzung des vorherigen Artikels darstellt, werden wir zum Abschnitt Pfade übergehen, um mit der Codegenerierung zu beginnen.
Der Pfad ist der REST-Endpunkt der API. Diese Definitionen sind ein wichtiger Bestandteil beim Erstellen eines REST-Endpunkts. Fehler in diesem Prozess können in Zukunft zu Refactoring und störenden Änderungen führen, was für Servicebenutzer unpraktisch sein kann. Tatsächlich weisen REST-Endpunkte in der Regel falsche Definitionen auf. Die schlechten Praktiken bei REST-Implementierungen sind so zahlreich, dass Sie überrascht sein werden, wenn Sie die richtige finden.
Der für die Ressource ausgewählte Pfad hat zwei Formen:
Das erste Format dient zum Abrufen einer Sammlung oder zum Erstellen eines neuen Datensatzes (gemäß der verwendeten HTTP-Methode), und das zweite Format dient zum Abrufen, Aktualisieren und Löschen eines bestimmten Datensatzes mit einem Primärschlüssel.
In der folgenden Definition beziehen sich alle Antworten auf Happy Path-Antworten. GetVitamin liefert also nur eine erfolgreiche Antwort auf ein Vitaminobjekt. Es ist wichtig zu bedenken, dass wir, da wir OpenAPI, insbesondere das Liferay-Framework, in jedem Pfad nutzen, eine große Anzahl von Antworten haben, die Fehler und Ausnahmen enthalten können. Das Framework behandelt alle von ihnen, sodass Sie nur auf erfolgreiche Antworten achten müssen.
Der erste Weg ist also der, der verwendet wird, um die Liste der Vitamine / Mineralien zu erhalten, und verwendet Paging, anstatt die gesamte Liste auf einmal zurückzugeben.
paths:
"/vitamins":
get:
tags: ["Vitamin"]
description: Retrieves the list of vitamins and minerals. Results can be paginated, filtered, searched, and sorted.
parameters:
- in: query
name: filter
schema:
type: string
- in: query
name: page
schema:
type: integer
- in: query
name: pageSize
schema:
type: integer
- in: query
name: search
schema:
type: string
- in: query
name: sort
schema:
type: string
responses:
200:
description: ""
content:
application/json:
schema:
items:
$ref: "#/components/schemas/Vitamin"
type: array
application/xml:
schema:
items:
$ref: "#/components/schemas/Vitamin"
type: array
Eine GET-Anfrage für / vitamins
gibt eine Reihe von Vitaminobjekten zurück. Auf der Swagger-Seite sehen Sie tatsächlich einen anderen Komponententyp namens "PageVitamin", der das Array mit den erforderlichen Paging-Details umschließt.
** Hinweis: Das Attribut tags ist hier wichtig. Dieser Wert entspricht dem Komponententyp, für den der Pfad ausgeführt wird, oder dem zurückgegebenen Komponententyp. Alle meine Methoden arbeiten mit Vitaminkomponenten, daher sind alle Tag-Werte gleich "[" Vitamin "]". Dies ist für die Codegenerierung unbedingt erforderlich. ** ** **
Wie viele Liferay Headless-APIs unterstützt es auch die Suche, Filterung, Paging-Steuerung und Elementsortierung.
Sie können die POST-Methode im selben Pfad verwenden, um ein neues Vitamin- / Mineralobjekt zu erstellen.
post:
tags: ["Vitamin"]
description: Create a new vitamin/mineral.
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Vitamin"
application/xml:
schema:
$ref: "#/components/schemas/Vitamin"
responses:
200:
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/Vitamin"
application/xml:
schema:
$ref: "#/components/schemas/Vitamin"
Der Hauptteil der Anfrage ist das erstellte Vitaminobjekt und die Antwort ist die neu erstellte Instanz.
Das zweite URL-Formular funktioniert für einen einzelnen Datensatz. Im ersten Beispiel erhält die GET-Anforderung ein einzelnes Vitaminobjekt mit der angegebenen "vitaminId".
"/vitamins/{vitaminId}":
get:
tags: ["Vitamin"]
description: Retrieves the vitamin/mineral via its ID.
parameters:
- name: vitaminId
in: path
required: true
schema:
type: string
responses:
200:
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/Vitamin"
application/xml:
schema:
$ref: "#/components/schemas/Vitamin"
Sie können eine PUT-Anforderung verwenden, um das aktuelle Vitaminobjekt durch das im Anforderungshauptteil enthaltene Objekt zu ersetzen. Felder, die nicht in der Anforderung enthalten sind, müssen im ersetzten Datensatz leer oder "null" sein.
put:
tags: ["Vitamin"]
description: Replaces the vitamin/mineral with the information sent in the request body. Any missing fields are deleted, unless they are required.
parameters:
- name: vitaminId
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Vitamin"
application/xml:
schema:
$ref: "#/components/schemas/Vitamin"
responses:
200:
description: Default Response
content:
application/json:
schema:
$ref: "#/components/schemas/Vitamin"
application/xml:
schema:
$ref: "#/components/schemas/Vitamin"
Die Anfrage enthält ein Vitamin, das das vorhandene ersetzt, und die Antwort ist ein neues Vitaminobjekt.
Sie können auch die PATCH-Anfrage verwenden, um Ihre aktuellen Vitamine zu aktualisieren. Im Gegensatz zu PUT, bei dem nicht bereitgestellte Felder ausgeblendet werden, werden Felder, die nicht Teil der Anforderung in PATCH sind, in diesem Objekt nicht geändert.
patch:
tags: ["Vitamin"]
description: Replaces the vitamin/mineral with the information sent in the request body. Any missing fields are deleted, unless they are required.
parameters:
- name: vitaminId
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Vitamin"
application/xml:
schema:
$ref: "#/components/schemas/Vitamin"
responses:
200:
description: ""
content:
application/json:
schema:
$ref: "#/components/schemas/Vitamin"
application/xml:
schema:
$ref: "#/components/schemas/Vitamin"
Die Anfrage enthält ein Feld mit zu aktualisierenden Vitaminen und die Antwort ist das aktualisierte Vitaminobjekt.
Der letzte ist der Weg, um das Vitamin mit einer DELETE-Anfrage zu entfernen.
delete:
tags: ["Vitamin"]
description: Deletes the vitamin/mineral and returns a 204 if the operation succeeds.
parameters:
- name: vitaminId
in: path
required: true
schema:
type: string
responses:
204:
description: ""
content:
application/json: {}
In diesem Pfad befindet sich kein Anforderungs- oder Antworttext.
Mit dem Swagger-Editor können Sie Ihre API definieren, um eine klare Überprüfung der Funktionsweise Ihres Dienstes zu erhalten.
Wie Sie in der Abbildung oben sehen können, ist es visuell leicht zu verstehen!
Beim Erstellen einer Yaml-Datei bietet der Editor selbst großartige Funktionen wie kontextsensitive Hilfe und sofortiges Feedback zu Syntaxfehlern, die zum Verständnis der API-Konfiguration sehr hilfreich sein können.
Wenn Sie den Swagger Editor verwenden, vergessen Sie nicht, die Yaml-Datei in die IDE zu verschieben.
Sie können den neuen REST Builder aufrufen. Führen Sie den folgenden Befehl im Verzeichnis headless-vitamins-impl
aus.
$ ../../../gradlew buildREST
Wie ich haben Sie vielleicht versagt. Hier ist ein Teil der Ausgabe, wenn Sie zum ersten Mal buildREST
ausführen:
Exception in thread "main" Cannot create property=paths for JavaBean=com.liferay.portal.vulcan.yaml.openapi.OpenAPIYAML@1e730495
in 'string', line 1, column 1:
openapi: 3.0.1
^
Cannot create property=get for JavaBean=com.liferay.portal.vulcan.yaml.openapi.PathItem@23f7d05d
in 'string', line 8, column 5:
get:
^
Cannot create property=responses for JavaBean=com.liferay.portal.vulcan.yaml.openapi.Get@23986957
in 'string', line 9, column 7:
tags:
^
For input string: "default"
in 'string', line 36, column 9:
default:
^
[...Kürzung...]
> Task :modules:headless-vitamins-impl:buildREST FAILED
Warum hast du versagt? Der Nachricht fehlt die Spezifität und die Ursache kann nicht genau bestimmt werden.
Schauen wir uns noch einmal die OpenAPI Yaml-Datei an. Es scheint, dass es sich nicht um ein Inhaltsproblem handelt, da es im Swagger Editor problemlos angezeigt wird.
Als ich diese Datei mit der Datei verglich, die Liferay für das Headless-Modul verwendet, gab es viele Unterschiede. Ich habe das Blog bereits repariert, daher wird der Fehler nicht angezeigt. Einfach ausgedrückt liefert das einfache Yaml-Format nicht die erwarteten Ergebnisse mit dem Befehl build REST
, selbst im Swagger Editor-Format.
Nachfolgend finden Sie eine kurze Einführung in die Unterschiede:
Die Headless-Delivery-API von Yaml for Liferay verwendet viele Antworten als "Standard", die REST Builder nicht akzeptiert, und Sie müssen den tatsächlichen Antwortcode verwenden. Die Liferay Yaml-Datei auf Github verwendet den tatsächlichen Antwortcode.
Die Beschreibung des Komponentenabschnitts muss nicht in Anführungszeichen gesetzt werden, sondern im Pfadabschnitt.
--Beschreibung usw. kann in Online-Yaml eingeschlossen werden, aber REST Builder versucht, alles in einer Zeile zusammenzufassen.
/ v1.0
der URL sollte nicht in die Pfaddefinition aufgenommen werden.Es kann andere Unterschiede geben, die ich nicht bemerkt habe. Wenn Sie einen Fehler wie den oben genannten erhalten, erstellen Sie die Datei [Liferay Official](https://github.com/liferay/liferay-portal/blob/master/modules/apps/headless/headless-delivery/headless- Vergleichen Sie es mit Delivery-Impl / Rest-Openapi.yaml) und überprüfen Sie, wie das Kontingent verwendet wird und ob es dem gleichen Format entspricht.
Nach diesem Versuch und Irrtum wurde meine Yaml-Datei so formatiert, dass sie der von Liferay folgt, und der Code wurde erfolgreich generiert.
$ ../../../gradlew buildREST
Ergebnisse zum Erfolg:
> Task :modules:headless-vitamins-impl:buildREST
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/src/main/java/com/dnebinger/headless/vitamins/internal/jaxrs/application/HeadlessVitaminsApplication.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/json/BaseJSONParser.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/http/HttpInvoker.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/pagination/Page.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/pagination/Pagination.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/function/UnsafeSupplier.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/rest-openapi.yaml
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/src/main/java/com/dnebinger/headless/vitamins/internal/graphql/mutation/v1_0/Mutation.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/src/main/java/com/dnebinger/headless/vitamins/internal/graphql/query/v1_0/Query.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/src/main/java/com/dnebinger/headless/vitamins/internal/graphql/servlet/v1_0/ServletDataImpl.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/src/main/java/com/dnebinger/headless/vitamins/internal/resource/v1_0/OpenAPIResourceImpl.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-api/src/main/java/com/dnebinger/headless/vitamins/dto/v1_0/Vitamin.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/dto/v1_0/Vitamin.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/serdes/v1_0/VitaminSerDes.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-api/src/main/java/com/dnebinger/headless/vitamins/dto/v1_0/Creator.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/dto/v1_0/Creator.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/serdes/v1_0/CreatorSerDes.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/src/main/java/com/dnebinger/headless/vitamins/internal/resource/v1_0/BaseVitaminResourceImpl.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/src/main/resources/OSGI-INF/liferay/rest/v1_0/vitamin.properties
Writing vitamins/modules/headless-vitamins/headless-vitamins-api/src/main/java/com/dnebinger/headless/vitamins/resource/v1_0/VitaminResource.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-impl/src/main/java/com/dnebinger/headless/vitamins/internal/resource/v1_0/VitaminResourceImpl.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-client/src/main/java/com/dnebinger/headless/vitamins/client/resource/v1_0/VitaminResource.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-test/src/testIntegration/java/com/dnebinger/headless/vitamins/resource/v1_0/test/BaseVitaminResourceTestCase.java
Writing vitamins/modules/headless-vitamins/headless-vitamins-test/src/testIntegration/java/com/dnebinger/headless/vitamins/resource/v1_0/test/VitaminResourceTest.java
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
Daher ist dies das Ende von Teil 2 dieser Blogserie.
In [Teil 1] der Blog-Reihe (https://qiita.com/TsubasaHomma/items/df3f93c8c54daa9a058b) werden wir ein neues kopfloses API-Projekt erstellen, eine Yaml-Datei für die Konfiguration erstellen, Objekttypen definieren und API-Yaml-Dateien öffnen. Ich tat.
Als Fortsetzung dieses Teils haben wir alle Pfade (Endpunkte) der REST-Anwendung hinzugefügt. Wir haben einige häufig auftretende Probleme beim Erstellen einer OpenAPI-Yaml-Datei angesprochen und den Vergleich von Liferay-Dateien als Beispiel für den Fall eines BuildREST-Taskfehlers erläutert.
Ich beendete diesen Teil, indem ich erfolgreich buildREST aufrief, um Code für die neue kopflose API zu generieren.
Im nächsten Teil (https://qiita.com/TsubasaHomma/items/101f9e3cba6334f7da01) werden wir uns mit dem generierten Code befassen, um zu sehen, wo wir mit dem Hinzufügen von Logik beginnen müssen. Wir sehen uns wieder! https://github.com/dnebing/vitamins
Recommended Posts