[JAVA] Comment créer votre propre API headless à l'aide de REST Builder de Liferay (partie 2)

introduction

Dans la partie 1 de cette série (https://liferay.dev/blogs/-/blogs/creating-headless-apis-part-1), vous utiliserez les outils REST Builder de Liferay pour créer votre propre API headless personnalisée. Nous avons commencé un projet à construire. Nous avons démarré le projet et créé quatre modules pour vous présenter les sections Meta et Reusable Components du fichier OpenAPI Yaml.

Dans cet article, qui est une continuation de l'article précédent, nous allons passer à la section Chemins pour entrer dans la génération de code.

Définition du chemin

Le chemin est le point de terminaison REST de l'API. Ces définitions sont une partie importante de la création d'un point de terminaison REST. Toute erreur dans ce processus peut entraîner une refactorisation et des changements catastrophiques à l'avenir, ce qui peut être gênant pour les utilisateurs du service. En fait, les points de terminaison REST ont tendance à avoir des définitions incorrectes. Les mauvaises pratiques des implémentations REST sont si nombreuses que vous serez surpris lorsque vous trouverez la bonne.

Le chemin choisi pour la ressource a deux formes:

Le premier format consiste à récupérer une collection ou à créer un nouvel enregistrement (selon la méthode HTTP utilisée), et le second format consiste à récupérer, mettre à jour et supprimer un enregistrement spécifique avec une clé primaire.

Dans la définition ci-dessous, toutes les réponses font référence à des réponses Happy Path. Ainsi, getVitamin ne fournit une réponse réussie que sur un objet Vitamin. Il est important de garder à l'esprit que parce que nous exploitons OpenAPI, en particulier le framework Liferay, dans chaque chemin, nous avons un grand ensemble de réponses qui peuvent contenir des erreurs et des exceptions. Le framework les gère tous, vous n'avez donc qu'à faire attention aux réponses réussies.

Liste de toutes les vitamines

Ainsi, le premier chemin est celui utilisé pour obtenir la liste des vitamines / minéraux et utilise la pagination au lieu de renvoyer la liste entière à la fois.

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

Une requête GET pour / vitamins renvoie un tableau d'objets Vitamin. Du côté Swagger, vous verrez en fait un autre type de composant appelé «PageVitamin» qui enveloppe le tableau avec les détails de pagination requis.

** Remarque: L'attribut tags ici est important. Cette valeur correspond au type de composant sur lequel opère le chemin ou au type de composant renvoyé. Toutes mes méthodes fonctionnent avec des composants Vitamin, donc toutes les valeurs de balises sont les mêmes [" Vitamin "]. Ceci est absolument nécessaire pour la génération de code. ** **

Comme de nombreuses API sans tête Liferay, il prend également en charge la recherche, le filtrage, le contrôle de pagination et le tri des éléments.

Faire des vitamines

Vous pouvez utiliser la méthode POST dans le même chemin pour créer un nouvel objet vitaminé / minéral.

    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"

Le corps de la demande sera l'objet vitamine créé et la réponse sera l'instance nouvellement créée.

Obtenez des vitamines

Le deuxième formulaire URL fonctionne pour un seul enregistrement. Dans le premier exemple, la requête GET obtient un seul objet Vitamin avec le «vitaminId» spécifié.

  "/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"

Échange de vitamines

Vous pouvez utiliser une requête PUT pour remplacer l'objet vitamin actuel par l'objet contenu dans le corps de la requête. Les champs non inclus dans la demande doivent être vides ou «null» dans l'enregistrement remplacé.

    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"

La demande contient une vitamine qui remplace celle existante et la réponse est un nouvel objet vitamine.

Renouvellement des vitamines

Vous pouvez également utiliser la demande PATCH pour mettre à jour vos vitamines actuelles. Contrairement à PUT, qui efface les champs qui ne sont pas fournis, les champs qui ne font pas partie de la requête dans PATCH ne sont pas modifiés dans cet objet.

    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"

La demande contiendra un champ de vitamines à mettre à jour et la réponse sera l'objet de vitamines mis à jour.

Supprimer les vitamines

Le dernier est le chemin pour supprimer la vitamine à l'aide d'une demande DELETE.

    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: {}

Il n'y a pas de corps de requête ou de corps de réponse dans ce chemin.

Vérifiez le résultat

Vous pouvez utiliser l'éditeur Swagger pour définir votre API pour un examen clair du fonctionnement de votre service.

Swagger Editorの結果確認画面

Comme vous pouvez le voir dans la figure ci-dessus, c'est facile à comprendre visuellement!

Lors de la création d'un fichier Yaml, l'éditeur lui-même fournit d'excellentes fonctionnalités telles qu'une aide contextuelle et un retour immédiat sur les erreurs de syntaxe, ce qui peut être très utile pour comprendre la configuration de l'API.

Si vous utilisez Swagger Editor, n'oubliez pas de déplacer le fichier Yaml vers l'EDI.

Essai de génération de code partie 1

Vous êtes prêt à appeler le nouveau REST Builder. Exécutez la commande suivante dans le répertoire headless-vitamins-impl.

$ ../../../gradlew buildREST

Comme moi, vous avez peut-être échoué. Voici une partie de la sortie lorsque vous exécutez pour la première fois buildREST:

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:
            ^
[...réduction...]
> Task :modules:headless-vitamins-impl:buildREST FAILED

Pourquoi avez-vous échoué? Le message manque de spécificité et la cause ne peut être déterminée avec précision.

Jetons à nouveau un coup d'œil au fichier OpenAPI Yaml. Il semble que ce ne soit pas un problème de contenu car il s'affiche sans problème dans Swagger Editor.

Ensuite, lorsque j'ai comparé ce fichier avec celui que Liferay utilise pour le module headless, il y avait de nombreuses différences. J'ai déjà corrigé le blog, donc je ne vois pas l'erreur. Pour le dire clairement, le format Yaml simple ne donne pas les résultats attendus avec la commande build REST, même au format Swagger Editor.

Voici une brève introduction aux différences:

L'API de livraison sans tête de Yaml for Liferay utilise de nombreuses réponses par défaut, ce que REST Builder n'accepte pas et vous devez utiliser le code de réponse réel. Le fichier Liferay Yaml sur Github utilise le code de réponse réel.

La description de la section de composant n'a pas besoin d'être citée, mais elle le fait dans la section de chemin.

Il peut y avoir d'autres différences que je n'ai pas remarquées. Si vous obtenez l'erreur ci-dessus, créez le fichier [Liferay Official](https://github.com/liferay/liferay-portal/blob/master/modules/apps/headless/headless-delivery/headless- Comparez-le avec delivery-impl / rest-openapi.yaml) et vérifiez comment utiliser le quota et s'il est conforme au même format.

Essai de génération de code, partie 2

Après ces essais et erreurs, mon fichier Yaml a été formaté pour suivre celui de Liferay, et le code a été généré avec succès.

$ ../../../gradlew buildREST

Résultats sur le succès:

> 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

C'est donc la fin de la partie 2 de cette série de blogs.

Résumé

Dans la [Partie 1] de la série de blogs (https://qiita.com/TsubasaHomma/items/df3f93c8c54daa9a058b), nous travaillerons sur la création d'un nouveau projet d'API headless, la création d'un fichier yaml pour la configuration, la définition des types d'objets et l'ouverture des fichiers yaml de l'API. J'ai fait.

Dans le prolongement de cette partie, nous avons ajouté tous les chemins (endpoints) de l'application REST. Nous avons abordé certains points communs auxquels vous pourriez être confronté lors de la création d'un fichier yaml OpenAPI, et comment comparer les fichiers Liferay à titre d'exemple en cas d'erreur de tâche buildREST.

J'ai terminé cette partie en appelant avec succès buildREST pour générer du code pour la nouvelle API headless.

Dans la partie suivante (https://qiita.com/TsubasaHomma/items/101f9e3cba6334f7da01), nous allons creuser dans le code généré pour voir où nous devons commencer à ajouter de la logique. À la prochaine! https://github.com/dnebing/vitamins

Recommended Posts

Comment créer votre propre API headless à l'aide de REST Builder de Liferay (partie 2)
Comment créer votre propre API headless à l'aide de REST Builder de Liferay (partie 4)
Comment créer votre propre API headless à l'aide de REST Builder de Liferay (partie 1)
Comment créer votre propre contrôleur correspondant à / error avec Spring Boot
Comment créer votre propre annotation en Java et obtenir la valeur
Créons une API REST à l'aide de WildFly Swarm.
[Rails] Comment créer un graphique à l'aide de lazy_high_charts
Comment implémenter le verrouillage optimiste dans l'API REST
Comment créer des données de catégorie hiérarchique à l'aide de l'ascendance
Comment créer docker-compose
[Forge] Comment enregistrer votre propre Entité et Entité Render dans 1.13.2
Comment créer une partie d'espace réservé à utiliser dans la clause IN
Comment déployer jQuery dans les applications Rails à l'aide de Webpacker
Comment créer un portlet de générateur de services dans Liferay 7 / DXP
Comment lire un fichier MIDI à l'aide de l'API Java Sound
Comment utiliser l'API Chain
Comment utiliser @Builder (Lombok)
Créez vos propres annotations Java
Introduction à l'API EHRbase 2-REST
Comment créer une méthode
Comment autoriser à l'aide de graphql-ruby
Comment créer un fichier jar et un fichier war à l'aide de la commande jar
[Rails 6] Comment créer un écran de saisie de formulaire dynamique à l'aide de cocoon
Un moyen simple de créer une classe de mappage lors de l'utilisation de l'API