Vous cherchez un moyen facile de partager vos types (modèles, DTOs, controllers, etc) entre une application Angular et une application Spring Boot ? Vous êtes au bon endroit !
Ce que nous allons réaliser dans ce petit tutoriel s’appelle de la “End-to-end (e2e) typesafety”, traduisible par “Sécurité de type bout-en-bout”.
Lorsque l'on parle de cela, on fait référence à la sécurité de type qui est assurée de bout en bout, c'est-à-dire de l'interface utilisateur de l'application (dans notre cas, AngularAngular est un framework de développement JavaScript populaire basé sur TypeScript.) jusqu'à la couche d'accès aux données de l'application (ici, Spring BootFramework Java se basant sur Spring.). L'objectif est de garantir la cohérence et la compatibilité des types utilisés entre les différentes couches de l'application. C'est parti !
Si les types ne sont pas cohérents entre les différentes couches de l'application, cela peut entraîner des erreurs et des bugs difficiles à identifier et à corriger. En outre, cela peut rendre le développement plus fastidieux et plus lent, car les développeurs doivent constamment traduire les types d'une couche à l'autre.
La sécurité de type bout-en-bout peut aider à éviter ces problèmes en s'assurant que les types sont cohérents et compatibles entre les différentes couches de l'application.
Il s’agit d’un réel avantage assurant à la fois une vitesse de développement accrue couplée à une robustesse de code bien plus importante.
Dans ce tutoriel, nous allons mettre en place un système qui va :
Vous l’aurez compris, avec cette technique on se base sur le back-end comme seule source de vérité. Cela n’implique donc pas de définir un contrat API mutualisé en amont du développement, rendant la chose plus flexible. Ici, le front-end va s’accorder automatiquement sur ce qui est déclaré au niveau du back-end.
Cette étape va être relativement facile puisqu’il s’agit simplement d’une librairie officielle Spring à ajouter dans ses dépendances Maven ou Gradle.
Exemple avec Maven et son
pom.xml:
<dependency>
<groupId>org.springdoc</groupId>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.4</version>
</dependency>
Il vous suffit ensuite de recharger les dépendances et de démarrer votre application, et vous pourrez voir le magnifique Swagger à l’adresse http://server:port//swagger-ui.html et le plus important, la spécification OpenAPI au format yaml à l’adresse http://server:port//v3/api-docs.yaml.
Nous allons maintenant créer un script dans notre projet Angular qui va s’occuper de télécharger cette spécification localement.
scripts/fetch_spec.mjs
import fetch from 'node-fetch'
import fs from 'fs/promises'
const options = {
baseUrl: 'http://localhost:8080/api',
output: 'api-docs.yaml'
}
/**
* Download the OpenAPI spec file from the API
* (it must be running when this script is executed!)
* and save it to the file system
*/
async function downloadOpenApiSpec() {
try {
const response = await fetch(options.baseUrl + '/v3/api-docs.yaml')
const data = await response.text()
await fs.writeFile(options.output, data)
console.log('Spécification OpenAPI de l\'API téléchargée avec succès.')
} catch (e) {
console.error(e.message)
}
}
downloadOpenApiSpec()
Vous pouvez maintenant télécharger la spécification OpenAPI de votre back-end Spring Boot, pour peu que celui-ci tourne en même temps sur votre machine !
Pour cette dernière partie, nous allons encore une fois créer un script JavaScriptLangage de scripting orienté objet dans notre projet, qui utilisera la superbe librairie npm ng-openapi-gen
.
Cette librairie génère automatiquement les interfaces des différents modèles présents dans la spécification OpenAPI, ainsi que des services client web pour effectuer des requêtes de manière totalement typée et au travers de fonctions (une fonction correspond à un endpoint d’un controller Spring). Tout ceci est inclus dans un ngModule afin d’être bien séparé du reste de votre code.
npm install -D ng-openapi-gen json-schema-ref-parser js-yaml node-fetch
Créez un deuxième script : scripts/gen.mjs
Copiez-y le code suivant :
import $RefParser from 'json-schema-ref-parser'
import { NgOpenApiGen } from 'ng-openapi-gen'
const options = {
input: 'api-docs.yaml',
output: 'src/app/api',
}
/**
* Generate Angular API module from the OpenAPI spec file
*/
async function generateAngularApiModule() {
// load the openapi-spec and resolve all $refs
const RefParser = new $RefParser()
const openApi = await RefParser.bundle(options.input, {
dereference: { circular: false }
})
const ngOpenGen = new NgOpenApiGen(openApi, options);
ngOpenGen.generate()
console.log('Module Angular généré avec succès.')
}
generateAngularApiModule()
package.json
:"scripts": {
//...
"update:api": "node scripts/fetch_spec.mjs && node scripts/gen.mjs",
"postinstall": "patch-package"
},
Seul hic avec cette librairie : les dates ne sont pas considérées du type Date mais en tant que string dans les interfaces de modèle générées.
Nous pouvons régler ça à l’aide de la très pratique librairie patch-package
!
Rendez-vous dans le fichier node_modules/ng-openapi-gen/lib/gen-utils.js
à peu près à la ligne 260
Juste avant le return
, rajoutez ce bout de code:
// A date
if (type === 'string' && schema.format === 'date-time') {
return 'Date';
}
npx patch-package ng-openapi-gen
git add
et git commit
le fichier nouvellement créé dans le dossier patches
npm install -D patch-package
package.json
:"scripts": {
//...
"postinstall": "patch-package"
},
Pour pouvoir utiliser les services clients auto-générés afin de faire nos requêtes sur l'APIUne API est un programme permettant à deux applications distinctes de communiquer entre elles et d’échanger des données., il vaut mieux que le type de retour des contrôleurs dans l'application Spring Boot soient définis, surtout ceux qui sont censés retourner du JSON.
Pour se faire, il suffit de rajouter une valeur à l'annotation @RequestMapping
d'une classe contrôleur.
Ex :
@RequestMapping(value = "/user", produces = "application/json")
Maintenant que tout est setup correctement, on peut commencer à travailler avec ce nouveau système !
Concrètement, à chaque fois que vous allez modifier/ajouter/supprimer une route sur votre application Spring Boot ou un modèle utilisé en paramètre d’entrée ou en sortie, vous n’aurez qu’à effectuer la commande Workflow
Maintenant que tout est setup correctement, on peut commencer à travailler avec ce nouveau système !
Concrètement, à chaque fois que vous allez modifier/ajouter/supprimer une route sur votre application Spring Boot ou un modèle utilisé en paramètre d’entrée ou en sortie, vous n’aurez qu’à effectuer la commande npm run update:a
dans le projet Angular afin de mettre à jour les types et services auto-générés. Attention : gardez bien en mémoire que l’application Spring Boot doit être démarrée au moment où vous exécutez la commande.
Vous avez maintenant la possibilité d’utiliser directement les interfaces des modèles dans votre code, et surtout d’utiliser les différents services clients autogénérés !
Un service correspond à un fichier controller de votre application Spring Boot, et ce même service contient une méthode par route afin de l’appeler tout en ayant un retour déjà typé avec le bon modèle.
Enfin, n’hésitez pas à vous renseigner sur la documentation de ng-openapi-gen (accessible par ici) pour savoir comment customiser les templates servant de base aux fichiers auto-générés, passer des headers et customiser les requêtes faites dans les services clients web, etc.
Ce système, relativement simple à mettre en place, offre tellement d’avantages qu’il serait dommage de ne pas en bénéficier !
Ce tuto vous a plu ? N'hésitez pas à nous faire part de vos retours via LinkedIn ou par mail :)
Quand la connectivité et l'interopérabilité des SI sont essentielles, les contrats API sont devenus un outil incontournable pour les entreprises. Ces derniers sont des documents qui définissent l'ensemble des fonctionnalités et des données qu'une API expo
NGINX est devenu sans conteste l'un des serveurs web les plus populaires essentiellement pour les raisons suivantes
Supprimer les jsessionid des urls pour un meilleur référencement de vos pages dans les applications JEE