Configuration de l'API Mocking avec Mirage JS et Vue.js
Publié: 2022-03-10À l'ère du SPA et de la JAMstack, il y a toujours eu une séparation des préoccupations entre les API et le développement frontal. Presque tous les projets JavaScript qui peuvent être découverts dans la nature interagissent avec un service Web ou une API et l'utilisent pour des authentifications ou pour obtenir des données relatives à l'utilisateur.
Ainsi, chaque fois que vous travaillez sur un projet et que l'API nécessaire n'a toujours pas été implémentée par l'équipe back-end ou que vous devez tester rapidement une fonctionnalité, vous disposez de certaines des options suivantes :
- Vous pouvez utiliser un proxy vers une version exécutée localement de votre backend réel, ce que, dans la plupart des cas, en tant que développeur front-end, vous n'auriez pas.
- Vous pouvez commenter la demande réelle et la remplacer par des données fictives. (C'est correct mais pas si génial car vous auriez besoin d'annuler cela pour passer en production et vous ne pourrez peut-être pas gérer les états et la latence du réseau.)
Qu'est-ce que l'API se moquant ?
La moquerie d'API est une imitation ou une simulation d'une API réelle. Cela est principalement fait dans le but d'intercepter les requêtes censées être adressées à une API backend réelle, mais cette moquerie existe sur votre frontend.
Pourquoi est-il important de se moquer de l'API ?
La moquerie d'API est très importante à bien des égards :
- Cela permet une très bonne expérience de développement frontal de ne pas dépendre des API de production avant de créer des fonctionnalités.
- Vous pourriez partager l'intégralité de votre frontend et cela fonctionnerait sans dépendre d'une véritable API backend.
Qu'est-ce que Mirage JS ?
Mirage JS a été créé il y a 5 ans et était assez utilisé dans la communauté Ember avant que Sam Selikoff n'annonce officiellement sa sortie le 24 janvier 2020 sur Twitter.
Mirage JS résout le problème du test des API backend sans dépendre de ces API. Il permet une expérience de développement frontale transparente en se moquant des API de production.
Mirage JS est une bibliothèque de simulation d'API pour les frameworks Vue.js, React, Angular et Ember
Qu'est-ce qui fait de Mirage JS un meilleur choix ?
Il y a eu d'autres options pour se moquer de l'API (comme les intercepteurs Axios, le serveur JSON de Typicode, etc.), mais ce que je pense être assez intéressant à propos de Mirage, c'est qu'il ne gêne pas votre processus de développement (comme vous le verriez quand nous l'avons configuré avec Vue dans un instant). Il est léger et pourtant puissant.
Il est livré avec une batterie incluse prête à l'emploi qui vous permet de reproduire des scénarios de consommation d'API de production réelle, comme la simulation d'un réseau lent avec son option de synchronisation.
Premiers pas avec Mirage JS et Vue.js
Maintenant que vous savez ce qu'est Mirage JS et pourquoi il est important pour votre flux de travail de développement frontal, examinons comment le configurer avec le framework Web progressif : Vue.js.
Création d'un projet Vue Green-Field (installation propre)
À l'aide de Vue CLI, créez un nouveau projet Vue.js en accédant au répertoire dans lequel vous souhaitez que le projet soit créé et exécuté (dans votre terminal):
vue create miragejs-demo-vue
La commande ci-dessus configurerait un nouveau projet Vue dans lequel vous pouvez maintenant vous cd
et exécuter soit yarn serve
ou npm run serve
.
#Installer Mirage JS
Installons maintenant Mirage JS en tant que dépendance de développement dans notre projet Vue.js en exécutant la commande suivante :
yarn add -D miragejs
Ou si vous utilisez NPM, lancez ceci :
npm install --save-dev miragejs
Et c'est tout! Mirage JS est maintenant installé dans notre projet Vue.js.
simulons quelque chose
Avec Mirage JS installé, voyons comment nous le configurons pour parler à Vue et simuler une API de todos de base (une API qui renvoie une liste de todos).
Définissez votre serveur
Pour commencer, nous devons créer un fichier server.js dans le répertoire /src
de notre projet Vue.js. Après cela, ajoutez ce qui suit :
import { Server, Model } from 'miragejs' export function makeServer({ environment = "development" } = {}) { let server = new Server({ environment, models: { todo: Model, }, seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) }, routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) }, }) return server }
Code expliqué
Tout d'abord, le fichier server.js est la façon dont vous configurez Mirage JS pour créer une nouvelle instance de son serveur fictif (faux) qui interceptera tous les appels d'API que vous effectuez dans votre application correspondant aux routes que vous définissez.
Maintenant, je suis d'accord que ce qui précède peut être écrasant au début, mais regardons de plus près ce qui se passe ici :
import { Server, Model } from 'miragejs'
À partir de l'extrait de code ci-dessus, nous importons Server
et Model
à partir de miragejs
.
-
Server
Il s'agit d'une classe exposée par Mirage pour nous aider à instancier une nouvelle instance d'un serveur Mirage JS pour "servir" de faux serveur. -
Model
Une autre classe exposée par Mirage pour aider à créer des modèles (un modèle détermine la structure d'une entrée de base de données Mirage JS) alimenté par l'ORM de Mirage.
export function makeServer({ environment = "development" } = {}) {}
Ce qui précède exporte essentiellement une fonction appelée makeServer
à partir de src/server.js
. Vous pouvez également noter que nous transmettons un paramètre d'environnement et que nous définissons le mode d'environnement de Mirage sur development
(vous nous verrez passer l'environnement de test plus loin dans cet article).
Le corps de makeServer
Maintenant, nous faisons quelques choses dans le corps de makeServer
. Nous allons jeter un coup d'oeil:
let server = new Server({})
Nous instancions une nouvelle instance de la classe Server et lui transmettons une option de configuration. Le contenu des options de configuration aide à configurer mirage :
{ environment, models: { todo: Model, }, seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) }, routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) }, }
Tout d'abord, nous passons le paramètre environment
que nous avons initialisé dans la définition de la fonction.
models: { todo: Model, },
L'option suivante qui est l'option des models
prend un objet des différents modèles dont nous voulons que Mirage se moque.
Dans ce qui précède, nous voulons simplement un modèle de tâches que nous instancions à partir de la classe Model.
seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) },
L'option suivante est la méthode seeds qui prend un paramètre appelé server
. La méthode des graines permet de créer des graines (les graines sont des données initiales ou une entrée dans la base de données de Mirage) pour nos modèles. Dans notre cas, pour créer les graines du modèle todo, nous faisons :
server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" })
le serveur a donc une méthode create qui attend comme premier argument une chaîne qui correspond au nom du modèle, puis un objet qui contiendra les propriétés ou attributs d'une graine particulière.
routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) },
enfin, nous avons la méthode routes qui définit les différentes routes (les routes sont nos points de terminaison d'API fictifs) Mirage JS va se moquer. Regardons le corps de la méthode :
this.namespace = "api"
cette ligne configure l'espace de noms pour toutes les routes, ce qui signifie que notre route todo est désormais accessible depuis /api/todos.
this.get("/todos", schema => { return schema.todos.all() })
Ce qui précède crée une route get et son gestionnaire utilise la méthode this.get()
. La méthode get()
attend la route, c'est-à-dire "/todos" et une fonction de gestionnaire qui prend le schema
en argument. L'objet de schéma est la façon dont vous interagissez avec l'ORM de Mirage qui est alimenté par la base de données en mémoire Mirage JS.
Finalement:
return schema.todos.all()
Nous renvoyons une liste de toutes nos tâches, en utilisant l'objet schéma rendu possible par l'ORM de Mirage.
src/main.js
Nous avons donc fini de configurer src/server.js
mais Vue ne le sait pas (du moins pas encore). Alors importons-le dans notre fichier main.js comme ceci :
import { makeServer } from "./server"
Ensuite, nous appelons la fonction makeServer
comme suit :
if (process.env.NODE_ENV === "development") { makeServer() }
Le if
conditionnel ci-dessus est une garde pour s'assurer que Mirage ne fonctionne qu'en développement.
Configuration terminée !
Nous avons maintenant configuré Miragejs avec Vue. Voyons-le en action. Dans notre fichier App.vue , nous effacerions le contenu et le remplacerions par l'extrait ci-dessous :
<template> <ul> <li v-for="todo in todos" v-bind:key="todo.id">{{ todo.content }}</li> </ul> </template> <script> export default { name: 'app', data() { return { todos: [] } }, created() { fetch("/api/todos") .then(res => res.json()) .then(json => { this.todos = json.todos }) } } </script>
Si vous êtes familier avec Vue.js, ce qui précède ne serait pas nouveau mais pour être total, ce que nous faisons est de faire une requête API en utilisant fetch
lorsque notre composant App.vue
est créé, puis nous transmettons les données renvoyées au tableau todos dans notre état de composant. Ensuite, nous utilisons un v-for pour itérer le tableau todos et afficher la propriété content de chaque todo.
Où est la partie Mirage JS ?
Si vous remarquez, dans notre composant App.vue, nous n'avons rien fait de spécifique à Mirage, nous faisons juste un appel API comme nous le ferions normalement. Cette fonctionnalité de Mirage est vraiment géniale pour DX car sous le capot, Mirage intercepterait toutes les requêtes qui correspondent à l'une des routes définies dans src/server.js pendant que vous êtes en développement.
C'est assez pratique car aucun travail ne serait nécessaire de votre part pour passer à un serveur de production réel lorsque vous êtes dans un environnement de production à condition que les itinéraires correspondent à vos points de terminaison d'API de production.
Redémarrez donc votre serveur de développement Vue via yarn serve
pour tester Mirage JS.
Vous devriez voir une liste de deux tâches. Une chose que vous trouverez assez intéressante est que nous n'avons pas eu besoin d'exécuter une commande de terminal pour démarrer Mirage, car il supprime cette surcharge en s'exécutant dans le cadre de votre application Vue.js.
Utilitaires de test Mirage JS et Vue
Si vous utilisez déjà Vue Test-utils dans votre application Vue, vous trouverez intéressant de savoir que Mirage peut facilement travailler avec lui pour simuler les requêtes réseau. Voyons un exemple mis en place à l'aide de notre application todos.
Nous utiliserions Jest pour nos tests unitaires. Donc, si vous suivez, vous pouvez à peu près utiliser la CLI Vue pour installer le plugin @vue/unit-jest
comme ceci :
vue add @vue/unit-jest
Ce qui précède installera les dépendances de développement @vue/cli-plugin-unit-jest
et @vue/test-utils
tout en créant un répertoire tests
et un fichier jest.config.js . Il ajoutera également la commande suivante dans notre section de scripts
package.json (assez soignée):
"test:unit": "vue-cli-service test:unit"
Testons !
Nous mettrons à jour notre App.vue pour qu'il ressemble à ceci :
<!-- src/App.vue --> <template> <div v-if="serverError" data-test> {{ serverError }} </div> <div v-else-if="todos.length === 0" data-test> No todos! </div> <div v-else> <ul> <li v-for="todo in todos" v-bind:key="todo.id" :data-test > {{ todo.content }} </li> </ul> </div> </template> <script> export default { name: "app", data() { return { todos: [], serverError: null, } }, created() { fetch("/api/todos") .then(res => res.json()) .then(json => { if (json.error) { this.serverError = json.error } else { this.todos = json.todos } }) }, } </script>
Rien de vraiment épique ne se passe dans l'extrait ci-dessus; nous structurons simplement pour permettre les tests de réseau que nous implémenterions avec notre test unitaire.
Bien que Vue CLI ait déjà ajouté un dossier /tests
pour nous, je trouve que c'est une bien meilleure expérience lorsque mes tests sont placés à proximité des composants qu'ils testent. Créez donc un dossier /__tests__
dans src/
et créez un fichier App.spec.js à l'intérieur. (C'est également l'approche recommandée par Jest.)
// src/__tests__/App.spec.js import { mount } from "@vue/test-utils" import { makeServer } from "../server" import App from "../App.vue" let server beforeEach(() => { server = makeServer({ environment: "test" }) }) afterEach(() => { server.shutdown() })
Donc, pour configurer nos tests unitaires, nous importons la méthode de mount
de @vue/test-utils
, importons le serveur Miragejs que nous avons créé précédemment et enfin importons le composant App.vue
.
Ensuite, nous utilisons la fonction de cycle de vie beforeEach
pour démarrer le serveur Mirage JS tout en passant dans l'environnement de test. (N'oubliez pas que nous définissons par défaut l'environnement sur development
.)
Enfin, nous fermons le serveur à l'aide de server.shutdown
dans la méthode de cycle de vie afterEach
.
Nos Essais
Maintenant, étoffons notre test (nous adopterions la section de démarrage rapide des documents Mirage js. Ainsi, votre App.spec.js ressemblerait finalement à ceci :
// src/__tests__/App.spec.js import { mount } from "@vue/test-utils" import { makeServer } from "./server" import App from "./App.vue" let server beforeEach(() => { server = makeServer({ environment: "test" }) }) it("shows the todos from our server", async () => { server.create("todo", { id: 1, content: "Learn Mirage JS" }) server.create("todo", { id: 2, content: "Integrate with Vue.js" }) const wrapper = mount(App) // let's wait for our vue component to finish loading data // we know it's done when the data-testid enters the dom. await waitFor(wrapper, '[data-test]') await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe("Learn Mirage JS") expect(wrapper.find('[data-test]').text()).toBe("Integrate with Vue.js") }) it("shows a message if there are no todo", async () => { // Don't create any todos const wrapper = mount(App) await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe("No todos!") }) // This helper method returns a promise that resolves // once the selector enters the wrapper's dom. const waitFor = function(wrapper, selector) { return new Promise(resolve => { const timer = setInterval(() => { const todoEl = wrapper.findAll(selector) if (todoEl.length > 0) { clearInterval(timer) resolve() } }, 100) }) } afterEach(() => { server.shutdown() })
Remarque : Nous utilisons ici un assistant (tel que défini dans la documentation Mirage JS). Il renvoie une promesse qui nous permet de savoir quand les éléments que nous testons sont déjà dans le DOM.
Maintenant, lancez yarn test:unit
.
Tous vos tests devraient réussir à ce stade.
Tester différents états de serveur avec Mirage JS
Nous pourrions modifier notre serveur Mirage JS pour tester différents états de serveur. Voyons comment.
// src/__tests__/App.spec.js import { Response } from "miragejs"
Tout d'abord, nous importons la classe Response
de Mirage, puis nous créons un nouveau scénario de test comme ceci :
it("handles error responses from the server", async () => { // Override Mirage's route handler for /todos, just for this test server.get("/todos", () => { return new Response( 500, {}, { error: "The database is taking a break.", } ) }) const wrapper = mount(App) await waitFor(wrapper, '[data-test]') expect(wrapper.find('[data-test]').text()).toBe( "The database is taking a break." ) })
Exécutez votre test et tout devrait passer.
Conclusion
Cet article visait à vous présenter Mirage JS et à vous montrer comment il améliore l'expérience de développement front-end. Nous avons vu le problème que Mirage JS a créé pour résoudre (création d'un front-end prêt pour la production sans aucune API back-end réelle) et comment le configurer avec Vue.js.
Bien que cet article ait effleuré la surface de ce que Mirage JS peut faire, je pense qu'il est suffisant pour vous aider à démarrer.
- Vous pouvez parcourir la documentation et rejoindre le serveur de discorde Mirage JS.
- Le référentiel de support pour cet article est disponible sur GitHub.
Les références
- Les documents Mirage
- Mirage Vue Démarrage rapide