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.
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.
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.
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.
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"
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.
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.
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.
Vous pouvez utiliser l'éditeur Swagger pour définir votre API pour un examen clair du fonctionnement de votre service.
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.
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.
tags: [" Vitamins "]
plutôt que la version en ligne./ v1.0
de l'URL affichée dans Swagger ne doit pas être incluse dans la définition du 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.
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.
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