Dans un environnement de développement, pour lancer dans le même temps votre application React et une API basée sur Node.js, vous pouvez imbriquer judicieusement les deux dépôts Git, puis utiliser un script NPM et quelques packages bien pratiques tels que concurrently et nodemon pour lancer les deux serveurs d'une seule commande. Pratique ! D'autant que pour contourner les restrictions d'accès liées à la politique de même origine, create-react-app permet le paramétrage d'un proxy pour vos requêtes API.
La généralisation des architectures dites "API first" répond à des impératifs humains et techniques très divers. En ce qui concerne l'organisation du travail des développeurs, c'est l'assurance de pouvoir scinder l'implémentation de l'accès aux données -aux ressources- d'une part, et le travail sur l'UI/UX, d'autre part. Un premier groupe peut concevoir une API robuste et proposer un "contrat" clair à l'équipe frontend qui accède aux données avec un référentiel unique, que l'application soit web ou mobile.
De cette façon, la conception de l'interface utilisateur est libérée d'une grande partie des contraintes qui régissent les architectures MVC traditionnelles. Le développeur peut ainsi mieux se concentrer sur la qualité de sa réponse aux spécifications fonctionnelles.
Si l'architecture de votre projet est de ce type, et que vous attaquez la conception d'un frontend SPA React avec create-react-app (quelle bonne idée !), ce qui suit peut vous éclairer. Nous allons voir comment il est possible d'accéder sans se compliquer la vie à une API RESTful basée sur Node.js, en imbriquant correctement ses dépôts.
Le principe est le suivant : vous ne souhaitez pas forcément modifier l'API qui est implémentée par une autre équipe, ou par un collègue, mais vous devez y accéder facilement depuis votre application React.
Vous allez pour cela devoir travailler sur deux dépôts Git clonés : celui du frontend React contiendra par exemple celui de l'API, et un script NPM se chargera de lancer les deux applications, sur deux ports différents.
Faut-il utiliser un framework en particulier pour le backend ?
Absolument pas ! Pour ma part je travaille plus volontiers avec LoopBack,
mais tout ce que qui s'appuie sur Node.js fait l'affaire.
Mettons que votre projet React s'appelle my-react-frontend et que l'API qu'il consomme répond au doux nom de my-node-api.
my-react-frontend est cloné à la racine, c'est le projet parent. Il contient
au moins les répertoires src/
, public/
et node_modules/
générés par
create-react-app.
build/
peut également être présent si vous avez déjà lancé au moins une fois
la commande npm run build
.
A la racine de my-react-frontend, clonez le dépôt my-node-api.
Vous devez obtenir :
my-react-frontend/
-- my-node-api/
-- node_modules/
-- public/
-- src/
...
Ne nous attardons pas trop sur my-node-api
, qui peut être implémenté de très
nombreuses manières. Partons du principe qu'une fois lancé, le serveur expose
les ressources dont votre application a besoin sur http://localhost:3001
. Et
disons juste que si l'équipe backend vous signale une mise à jour, vous ferez
simplement :
cd my-node-api/
git pull
Faut-il forcément organiser les dépôts de cette façon ?
Pas du tout. Mais l'intérêt de cette configuration, c'est que le backend est "dans
sa bulle" et que les développeurs qui le font évoluer n'ont pas à organiser le code
en fonction de ce frontend en particulier.
Dernière chose importante : pensez à ajouter my-node-api/
au fichier
.gitignore
du projet React. Il ne faudrait évidemment pas qu'il versionne le
backend.
En production, il est fréquent d'utiliser le même serveur pour servir l'application React et l'API sous-jacente. Dans cette configuration, le mécanisme de Cross-origin resource sharing (CORS), basé sur des headers HTTP, n'a pas à être implémenté.
En développement, par contre, il est plus pratique de dissocier les serveurs pour bénéficier de toutes les fonctionnalités de l'écosystème React.
Pour répondre à cette contrainte, create-react-app propose un mécanisme qui permet de mettre en place un proxy d'API.
En partant du principe que votre frontend écoute sur le port 3000, et le serveur
API sur le port 3001, il suffit d'ajouter un paramètre au premier niveau du
package.json
:
{
"proxy": "http://localhost:3001"
}
De cette façon, vous pourrez utiliser un chemin relatif pour accéder à vos
ressources. Si une requête ne concerne pas un asset statique, elle sera
relayée vers votre backend. fetch('/api/bananas')
, par exemple, requêtera
notre API sur http://localhost:3001/api/bananas
.
Nous utiliserons pour cela un script NPM défini dans le package.json
situé à
la racine du projet React.
Deux petits outils seront nécessaires pour créer le script ad hoc :
concurrently
qui
permet de lancer plusieurs scripts en une seule commande. Faites par exemple
un npm install --save-dev concurrently
.nodemon
qui scrute votre
backend Node.js et relance le serveur automatiquement en cas de modification
du code. Faites donc un npm install --save-dev nodemon
, vous ne le
regretterez pas.Tout est prêt ! Ouvrez package.json
et ajoutez dans les scripts
:
"start-with-api": "concurrently \"react-scripts start\" \"PORT=3001 nodemon ./my-node-api/server/server.js\""
Le chemin d'accès au script serveur est à adapter en fonction de vos propres
choix techniques ! Notez que dans ce cas précis, on passe une variable
d'environnement PORT
que le script serveur utilise pour écraser son port
d'écoute par défaut.
Au final, le package.json
doit ressembler à ceci :
{
"name": "my-react-frontend",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:3001",
"scripts": {
"start": "react-scripts start",
"start-with-api":
"concurrently \"react-scripts start\" \"PORT=3001 nodemon ./my-node-api/server/server.js\"",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"react-scripts": "1.0.14",
"concurrently": "3.5.0",
"nodemon": "1.12.1"
},
"dependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0"
}
}
Pour mémoire, nous n'avons ajouté que deux lignes : "proxy" et "scripts/start-with-api".
Si le backend ne joue pas un grand rôle dans votre application ou si -plus
probablement- vous souhaitez démarrer sans attendre que le véritable backend
soit disponible, je vous conseille de tester l'excellent
json-server
.
Cet élégant package offre la possibilité de créer un fichier JSON avec quelques
données factices (data fixtures) et de les mettre à disposition de votre
application à la façon d'une API RESTful, grâce à un simple
json-server --watch db.json
.
Il va sans dire qu'en modifiant légèrement le script start-with-api, vous disposerez en quelques secondes d'un backend au poil pour votre nouvelle application.