Configuración de simulación de API con Mirage JS y Vue.js

Publicado: 2022-03-10
Resumen rápido ↬ Este artículo presenta Mirage JS, una biblioteca de simulación de API que le permite crear, probar y compartir una aplicación de JavaScript funcional completa sin tener que depender de ningún servicio o API de back-end. También aprenderá a configurar Mirage JS con el marco frontal progresivo, Vue.js.

En la era de SPA y JAMstack, siempre ha habido una separación de preocupaciones entre las API y el desarrollo front-end. Casi todos los proyectos de JavaScript que se pueden encontrar en la naturaleza interactúan con un servicio web o API y lo usan para autenticaciones u obtener datos relacionados con el usuario.

Por lo tanto, cada vez que esté trabajando en un proyecto y el equipo de back-end aún no haya implementado la API necesaria o necesite probar rápidamente una función, tiene algunas de las siguientes opciones:

  • Podría usar un proxy para una versión que se ejecuta localmente de su backend real que, en la mayoría de los casos, como desarrollador front-end, no tendría.
  • Puede comentar la solicitud real y reemplazarla con datos simulados. (Esto está bien, pero no es tan bueno, ya que tendría que deshacerlo para llegar a la producción y es posible que no pueda lidiar con los estados de red y la latencia).

¿Qué es la simulación de API?

La burla de API es una imitación o una simulación de una API real. Se realiza principalmente para interceptar solicitudes que se supone que deben realizarse en una API de back-end real, pero esta simulación existe en su interfaz.

¿Por qué es importante la simulación de API?

La simulación de API es significativamente importante en muchos sentidos:

  1. Es una muy buena experiencia de desarrollo front-end no depender de las API de producción antes de desarrollar funciones.
  2. Podría compartir su interfaz completa y funcionaría sin depender de una API de back-end real.
¡Más después del salto! Continúe leyendo a continuación ↓

¿Qué es Mirage JS?

Mirage JS se creó hace 5 años y se usó bastante en la comunidad de Ember antes de que Sam Selikoff anunciara oficialmente su lanzamiento el 24 de enero de 2020 en Twitter.

Mirage JS resuelve el problema de probar las API de back-end sin depender de esas API. Permite una experiencia de desarrollo front-end perfecta al simular las API de producción.

Mirage JS es una biblioteca de simulación de API para los marcos Vue.js, React, Angular y Ember

¿Qué hace que Mirage JS sea una mejor opción?

Ha habido otras opciones para la burla de API (como los interceptores Axios, el servidor JSON de Typicode, etc.), pero lo que creo que es bastante interesante sobre Mirage es que no se interpone en el proceso de desarrollo (como vería cuando lo configuramos con Vue en un momento). Es ligero y, sin embargo, potente.

Viene con una batería incluida de fábrica que le permite replicar escenarios de consumo de API de producción real, como simular una red lenta con su opción de tiempo.

Primeros pasos con Mirage JS y Vue.js

Entonces, ahora que sabe qué es Mirage JS y por qué es importante para su flujo de trabajo de desarrollo front-end, veamos cómo configurarlo con el marco web progresivo: Vue.js.

Creación de un proyecto Vue de campo verde (instalación limpia)

Usando la CLI de Vue, cree un nuevo proyecto Vue.js yendo al directorio en el que desea que se cree y ejecute el proyecto (en su terminal):

 vue create miragejs-demo-vue

El comando anterior configuraría un nuevo proyecto Vue en el que ahora puede ingresar y ejecutar yarn serve o cd npm run serve .

#Instalación de Mirage JS

Ahora instalemos Mirage JS como una dependencia de desarrollo en nuestro proyecto Vue.js ejecutando el siguiente comando:

 yarn add -D miragejs

O si está utilizando NPM, ejecute esto:

 npm install --save-dev miragejs

¡Y eso es! Mirage JS ahora está instalado en nuestro proyecto Vue.js.

Vamos a burlarnos de algo

Con Mirage JS instalado, veamos cómo lo configuramos para hablar con Vue y simular una API básica de todos (una API que devuelve una lista de todos).

Defina su servidor

Para comenzar, necesitamos crear un archivo server.js en el directorio /src de nuestro proyecto Vue.js. Después de eso, agregue lo siguiente:

 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 }

Código explicado

En primer lugar, el archivo server.js es la forma en que configura Mirage JS para crear una nueva instancia de su servidor simulado (falso) que interceptará todas las llamadas API que realice en su aplicación que coincidan con las rutas que defina.

Ahora, estoy de acuerdo en que lo anterior puede ser abrumador al principio, pero echemos un vistazo más de cerca a lo que está pasando aquí:

 import { Server, Model } from 'miragejs'

Desde el fragmento de código anterior, estamos importando el Server y el Model de miragejs .

  • Server
    Esta es una clase expuesta por Mirage para ayudarnos a crear instancias de una nueva instancia de un servidor Mirage JS para "servir" como nuestro servidor falso.
  • Model
    Otra clase expuesta por Mirage para ayudar en la creación de modelos (un modelo determina la estructura de una entrada de la base de datos de Mirage JS) con tecnología ORM de Mirage.
 export function makeServer({ environment = "development" } = {}) {}

Lo anterior básicamente exporta una función llamada makeServer desde src/server.js . También puede notar que estamos pasando un parámetro de entorno y configurando el modo de entorno de Mirage en development (nos verá pasando el entorno de prueba más adelante en este artículo).

El cuerpo de makeServer

Ahora estamos haciendo un par de cosas en el cuerpo de makeServer . Vamos a ver:

 let server = new Server({})

Estamos instanciando una nueva instancia de la clase Servidor y pasándole una opción de configuración. El contenido de las opciones de configuración ayuda a instalar 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() }) }, }

En primer lugar, estamos pasando el parámetro de environment que inicializamos en la definición de la función.

 models: { todo: Model, },

La siguiente opción, que es la opción de models , toma un objeto de los diferentes modelos que queremos que Mirage simule.

En lo anterior, simplemente queremos un modelo de tareas pendientes que estamos instanciando desde la clase Model.

 seeds(server) { server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" }) },

La siguiente opción es el método de semillas que toma un parámetro llamado server . El método de semillas ayuda a crear semillas (las semillas son datos iniciales o una entrada en la base de datos de Mirage) para nuestros modelos. En nuestro caso, para crear las semillas para el modelo de tareas pendientes, hacemos:

 server.create("todo", { content: "Learn Mirage JS" }) server.create("todo", { content: "Integrate With Vue.js" })

por lo que el servidor tiene un método de creación que espera como primer argumento una cadena que corresponde al nombre del modelo, luego un objeto que contendrá las propiedades o atributos de una semilla en particular.

 routes() { this.namespace = "api" this.get("/todos", schema => { return schema.todos.all() }) },

finalmente, tenemos el método de rutas que define las diversas rutas (las rutas son nuestros puntos finales de API simulados) que Mirage JS va a simular. Veamos el cuerpo del método:

 this.namespace = "api"

esta línea configura el espacio de nombres para todas las rutas, lo que significa que ahora se puede acceder a nuestra ruta de tareas pendientes desde /api/todos.

 this.get("/todos", schema => { return schema.todos.all() })

Lo anterior crea una ruta de obtención y su controlador utiliza el método this.get() . El método get() espera la ruta, es decir, "/todos" y una función de controlador que toma el schema como argumento. El objeto de esquema es cómo interactúa con el ORM de Mirage, que funciona con la base de datos en memoria de Mirage JS.

Finalmente:

 return schema.todos.all()

Estamos devolviendo una lista de todos nuestros todos, usando el objeto de esquema hecho posible por el ORM de Mirage.

src/principal.js

Así que hemos terminado de configurar src/server.js pero Vue no lo sabe (al menos no todavía). Importémoslo en nuestro archivo main.js así:

 import { makeServer } from "./server"

Luego llamamos a la función makeServer así:

 if (process.env.NODE_ENV === "development") { makeServer() }

Lo anterior, if es condicional, es una protección para asegurarse de que Mirage solo se ejecute en desarrollo.

¡Instalación completa!

Ahora hemos configurado Miragejs con Vue. Veámoslo en acción. En nuestro archivo App.vue , borraríamos el contenido y lo reemplazaríamos con el siguiente fragmento:

 <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 está familiarizado con Vue.js, lo anterior no sería nada nuevo, pero en aras de ser total, lo que estamos haciendo es realizar una solicitud de API usando fetch cuando se crea nuestro componente App.vue , luego pasamos los datos devueltos. a la matriz todos en nuestro estado de componente. Luego, estamos usando un v-for para iterar la matriz de todos y mostrar la propiedad de contenido de cada todo.

¿Dónde está la pieza Mirage JS?

Si observa, en nuestro componente App.vue, no hicimos nada específico para Mirage, solo estamos haciendo una llamada a la API como lo haríamos normalmente. Esta característica de Mirage es realmente excelente para DX porque, bajo el capó, Mirage interceptaría cualquier solicitud que coincida con cualquiera de las rutas definidas en src/server.js mientras está en desarrollo.

Esto es bastante útil porque no se necesitaría ningún trabajo de su parte para cambiar a un servidor de producción real cuando se encuentre en un entorno de producción, siempre que las rutas coincidan con los puntos finales de la API de producción.

Así que reinicie su servidor de desarrollo Vue a través de yarn serve para probar Mirage JS.

Debería ver una lista de dos todos. Una cosa que encontraría bastante interesante es que no necesitábamos ejecutar un comando de terminal para iniciar Mirage porque elimina esa sobrecarga al ejecutarse como parte de su aplicación Vue.js.

Utilidades de prueba de Mirage JS y Vue

Si ya está utilizando Vue Test-utils en su aplicación Vue, le resultará emocionante saber que Mirage puede trabajar fácilmente con él para simular solicitudes de red. Veamos un ejemplo de configuración usando nuestra aplicación Todos.

Estaríamos usando Jest para nuestras pruebas unitarias. Entonces, si está siguiendo, podría usar la CLI de Vue para instalar el complemento @vue/unit-jest esta manera:

 vue add @vue/unit-jest

Lo anterior instalará las dependencias de desarrollo @vue/cli-plugin-unit-jest y @vue/test-utils al mismo tiempo que crea un directorio de tests y un archivo jest.config.js . También agregará el siguiente comando en nuestra sección de secuencias de scripts package.json (bastante ordenado):

 "test:unit": "vue-cli-service test:unit"

¡Probemos!

Actualizaríamos nuestro App.vue para que se vea así:

 <!-- 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>

Nada realmente épico está pasando en el fragmento anterior; solo estamos estructurando para permitir la prueba de red que estaríamos implementando con nuestra prueba unitaria.

Aunque Vue CLI ya agregó una carpeta /tests para nosotros, creo que es una experiencia mucho mejor cuando mis pruebas se colocan cerca de los componentes que están probando. Así que cree una carpeta /__tests__ en src/ y cree un archivo App.spec.js dentro de ella. (Este es también el enfoque recomendado por 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() })

Entonces, para configurar nuestras pruebas unitarias, estamos importando el método de mount desde @vue/test-utils , importando el servidor Miragejs que creamos anteriormente y finalmente importando el componente App.vue .

A continuación, usamos la función de ciclo de vida beforeEach para iniciar el servidor Mirage JS mientras se pasa por el entorno de prueba. (Recuerde, configuramos de manera predeterminada el entorno para que sea development ).

Por último, estamos apagando el servidor usando server.shutdown en el método de ciclo de vida afterEach .

Nuestras Pruebas

Ahora, desarrollemos nuestra prueba (estaríamos adoptando la sección de inicio rápido de los documentos de Mirage js. Entonces, su App.spec.js finalmente se vería así:

 // 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() })

Nota : Estamos usando un ayudante aquí (como se define en los documentos de Mirage JS). Devuelve una promesa que nos permite saber cuándo los elementos que estamos probando ya están en el DOM.

Ahora ejecute yarn test:unit .

Todas sus pruebas deben pasar en este punto.

Prueba de diferentes estados del servidor con Mirage JS

Podríamos modificar nuestro servidor Mirage JS para probar diferentes estados del servidor. Veamos cómo.

 // src/__tests__/App.spec.js import { Response } from "miragejs"

Primero, importamos la clase Response de Mirage, luego creamos un nuevo escenario de prueba así:

 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." ) })

Ejecute su prueba y todo debería pasar.

Conclusión

Este artículo tuvo como objetivo presentarle Mirage JS y mostrarle cómo mejora la experiencia de desarrollo front-end. Vimos el problema que Mirage JS creó para abordar (construir un front-end listo para producción sin ninguna API de back-end real) y cómo configurarlo con Vue.js.

Aunque este artículo rascó la superficie de lo que Mirage JS puede hacer, creo que es suficiente para comenzar.

  • Puede consultar los documentos y unirse al servidor de discordia de Mirage JS.
  • El repositorio de apoyo para este artículo está disponible en GitHub.

Referencias

  • Los documentos de Mirage
  • Inicio rápido de Mirage Vue