https://hub.docker.com/_/postgres/). Une fois la base lancée, créez la base de l'application CREATE DATABASE cataloguedb
. Un exemple de configuration de l'application sur ma base locale PostgreSQL se trouve avec les sources dans application.properties
. Vous devrez certainement changer l'utilisateur, le mot de passe, l'adresse de la base et son port. Pour connaitre le port de votre base sur docker : docker inspect <containerId>
et trouvez HostPort
dans le champ NetworkSettings
.
Pour ne pas avoir à faire le pom.xml moi-même : https://start.spring.io
Sur cette interface vous pouvez spécifier les dépendances qui vous intéressent. Dans le cas présent, j'ai demandé :
Après avoir choisi vos dépendances sur ce site, cliquez sur "Generate Project", qui vous donnera un zip avec votre projet initialisé. Lancez votre application avec mvn spring-boot:run
, et hop, un serveur qui fonctionne.
Dans l'URL, chaque collection est le nom de la ressource au pluriel. Chaque ressource est accessible par un identifiant après le nom de la ressource. Les méthodes HTTP:
Sur l'objet API, le nom et la version sont uniques. Quand un POST est effectué avec un nom et une version que la base connait, le catalogue se contente de remplacer les autres champs par le nouvel objet qui lui est fourni. Si vous cherchez comment designer votre API, je vous conseille l'article "Designer une API REST" et sa refcard.
La Refcard API Design
L'accès se fait par la ressource de spécification correspondante, puis par l'ajout de "specificationFile" à la fin de l'URL. GET /specifications/1/specificationFile me parait un peu plus naturel que de passer par un endpoint différent.
Il aurait été possible de faire un endpoint pour la ressource qui décrit l'API, et un pour uploader le fichier de spécification. Mais plutôt que de laisser le consommateur gérer ce processus, j'ai préféré l'inclure dans l'interface. Ce type de choix peut être fait pour assurer la qualité de la donnée, mais aussi éviter que tout le monde réimplémente la même chose. La contrepartie c'est que l'interface nécessite de faire du multipart, et peut être moins simple à gérer selon les clients qui l'utiliseront. Mais dans notre cas, CURL (utilisable avec Jenkins) permet cela facilement, et pour une interface d'upload, ce n'est pas bien plus compliqué. Il n'y a pas de solution miracle universelle : L'architecture, c'est une histoire de compromis.
Du fait l'implémentation peu commune de la méthode de création de spécifications, Spring REST n'a pas créé automatiquement les méthodes CRUD. Ce n'est pas très grave dans la mesure où, pour certaines méthodes, des spécificités nécessiteraient qu'on fasse ce travail. C'est le cas de la suppression d'une specification, pour laquelle le fichier correspondant doit aussi être supprimé sur système de fichier. J'aurais cependant préféré que Spring génère automatiquement le code le plus direct et que je n'ai plus qu'à surcharger les méthodes que je voulais.
En regardant le code, vous remarquerez que je dois désérialiser les objets JSON et déclencher leur validation moi-même et donc gérer les aussi les cas d'erreur avec leur message. Pourquoi ne pas avoir utilisé un objet dans la signature de la méthode avec l'annotation @Validate ? Il est vrai qu’avec Spring je ne devrais même pas avoir à m’occuper de sérialiser ou désérialiser, il le fait automatiquement. Saut que cette fonctionnalité disparait bizarrement quand dans l'endpoint l'un des paramètres transforme cette requête en requête multipart. Après pas mal de recherche et d'essais, il semble que lorsque vous implémentez un endpoint multipart avec Spring, vous ne pouvez pas désérialiser automatiquement un objet. La conséquence directe est qu'il faut également se charger soi-même des étapes de validation et donc de gestion d'erreur…
À de nombreuses reprises Spring a tenté de me faire comprendre des choses sans me dire explicitement ce qu'il voulait ou pouvait faire. J'ai un peu lutté pour comprendre que je n'aurai pas toutes les méthodes CRUD gérées automagiquement par Spring à partir du moment où j'implémente l'une des méthodes. Je me suis cassé les dents sur le problème de désérialisation d'objet et de Multipart parce qu'il n'était pas clair que "Spring ne peut gérer les deux à la fois sur un même endpoint". Encore une fois, faites des tests. Votre santé mentale en dépend.
Les sources sont par ici : https://github.com/Aigrefin/api_catalogue. Et vous trouverez la spécification de l'API du catalogue, avec les sources, ici : https://github.com/Aigrefin/api_catalogue/blob/master/catalogue-api.apib.