[JAVA] So erstellen Sie Ihre eigene kopflose API mit Liferays REST Builder (Teil 2)

Einführung

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.

Pfaddefinition

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.

Liste aller Vitamine

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.

Vitamine herstellen

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.

Holen Sie sich Vitamine

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"

Vitaminaustausch

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.

Vitaminerneuerung

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.

Vitamine entfernen

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.

Überprüfen Sie das Ergebnis

Mit dem Swagger-Editor können Sie Ihre API definieren, um eine klare Überprüfung der Funktionsweise Ihres Dienstes zu erhalten.

Swagger Editorの結果確認画面

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.

Testversion zur Codegenerierung Teil 1

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.

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.

Testversion zur Codegenerierung Teil 2

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.

Zusammenfassung

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

So erstellen Sie Ihre eigene kopflose API mit Liferays REST Builder (Teil 2)
So erstellen Sie Ihre eigene kopflose API mit Liferays REST Builder (Teil 4)
So erstellen Sie Ihre eigene kopflose API mit Liferays REST Builder (Teil 1)
So erstellen Sie mit Spring Boot einen eigenen Controller, der / error entspricht
So erstellen Sie Ihre eigene Anmerkung in Java und erhalten den Wert
Erstellen wir eine REST-API mit WildFly Swarm.
[Rails] So erstellen Sie ein Diagramm mit lazy_high_charts
So implementieren Sie optimistisches Sperren in der REST-API
So erstellen Sie hierarchische Kategoriedaten mithilfe von Vorfahren
So erstellen Sie Docker-Compose
[Forge] So registrieren Sie Ihre eigene Entität und Ihr Entity Render in 1.13.2
So erstellen Sie ein Platzhalterteil zur Verwendung in der IN-Klausel
So stellen Sie jQuery in Rails-Apps mit Webpacker bereit
So erstellen Sie ein Service Builder-Portlet in Liferay 7 / DXP
So spielen Sie eine MIDI-Datei mit der Java Sound API ab
Verwendung der Ketten-API
Verwendung von @Builder (Lombok)
Erstellen Sie Ihre eigenen Java-Anmerkungen
Einführung in die EHRbase 2-REST-API
So erstellen Sie eine Methode
So autorisieren Sie mit graphql-ruby
So erstellen Sie eine JAR-Datei und eine War-Datei mit dem Befehl jar
[Rails 6] So erstellen Sie mit cocoon einen dynamischen Formular-Eingabebildschirm
Einfache Möglichkeit zum Erstellen einer Zuordnungsklasse bei Verwendung der API