El Manual del Desarrollador

Dominando Stubby: La Guía Definitiva paso a paso para Mockear el Backend

Desbloqueando Secretos del Desarrollo: Tu Guía Paso a Paso para Dominar Stubby

Code & Cozy
10 min readJun 9, 2023
by Pexels

Cuando trabajas con tecnologías front-end como ReactJS, es posible que te encuentres en situaciones en las que necesites incorporar código del lado del servidor y consultas complejas bases de datos. Esto puede resultar abrumador, especialmente cuando tu enfoque principal está en el lado del cliente. O tal vez estás en un equipo multidisciplinario con un colega de backend trabajando contigo de forma paralela, pero ¿qué sucede si el backend aún no está listo y necesitas probar los servicios? O eres un desarrollador full-stack y puedes hacer ambas cosas, pero ¿qué sucede si tienes poco tiempo y necesitas probar de inmediato las respuestas de un posible endpoint que aún no está listo? No te preocupes. Existe una solución llamada stubby4node.

Stubby4node es un fantástico paquete de npm que simplifica el proceso. Te permite crear un servidor ficticio que actúa como un verdadero backend durante el desarrollo. Puedes configurarlo fácilmente para responder a las solicitudes entrantes, imitando o simulando el comportamiento de sistemas externos. Es como tener una herramienta mágica que te ayuda a evitar las complejidades de configurar un backend completo.

Así que, escoge stubby4node y permítele ser tu arma secreta para un desarrollo más fluido. Di adiós a las preocupaciones de los backends incompletos y dale la bienvenida a una experiencia de desarrollo de front-end simplificada y atractiva.

En este post, vamos a instalar e implementar paso a paso stubby4node en un proyecto de ReactJS y NextJS, junto con una API REST, de la manera más sencilla posible. Desde la instalación hasta la creación de los servicios y la inicialización de todo el proyecto con stubby utilizando comandos.

P.D Puedes revisar también el respositorio en GithHub en el que dejé todo el código mencionado en este post.

#1 Instalación

Para instalar la biblioteca Stubby en tu proyecto, debes ir a la página oficial y copiar el comando npm. Este comando agregará el paquete stubby como un devDependency en tu archivo package.json.

npm install --save-dev stubby

Puedes encontrar mayor deatlles sobre la librería de stubby en su página de npm.

#2 Configuración

Crea una carpeta llamada stubby en el directorio principal de tu proyecto. Dentro de la carpeta stubby, crea un archivo llamado index.yaml. Este archivo contendrá la configuración de todos los endpoints que utilizarás en tu proyecto.

Aquí tienes un ejemplo de estructura de archivos:

.
├── src
│ ├── components
│ ├── pages
│ └── styles
├── stubby
│ └── index.yaml
├── README.md
├── jsconfig.json
├── next.config.js
├── package-lock.json
└── package.json

También revisar la propia documentación de stubby respecto a la configuración en su respositorio oficial.

#3 Crea los endpoints y respuestas

Ahora que has configurado la estructura, puedes agregar tus endpoints y sus respuestas correspondientes. Crea una carpeta dentro de la carpeta stubby. Dentro de esta carpeta, crea subcarpetas para cada endpoint y agrega los datos de respuesta en formato JSON.

Por ejemplo, si tienes un endpoint GET para obtener los datos de un usuario y un endpoint POST para crear un nuevo usuario, puedes crear una carpeta llamada usery subcarpetas llamadas get-user y create-new-user para representar estos endpoints.

P.D. Puedes llamar estas carpetas como tú quieras, pero para mantener coherencia, debe estar relacionado con los endpoints o el servicio que estás llamando, y también debes utilizar los mismos nombres de carpetas y archivos cuando los llames posteriormente.

Aquí tienes un ejemplo de estructura de archivos:

.
├── src
│ ├── components
│ ├── pages
│ └── styles
├── stubby
│ ├── create-new-user
│ │ └── data.json
│ ├── get-user
│ │ └── data.json
│ └── index.yaml
├── README.md
├── jsconfig.json
├── next.config.js
├── package-lock.json
└── package.json

En cada archivo data.json puedes agregar las respuestas reales que esperas desde el backend. Por ejemplo:

// get-user/data.json
{
"name": "Anita",
"email": "Smith"
}
// create-new-user/data.json
{
"status": 200,
"message": "User created successfully!",
"user": {
"id": 111,
"name": "Anita",
"email": "Smith"
}
}

<aside> 💡 Ten en cuenta que estos endpoints y respuestas solo funcionarán localmente y no en un entorno de producción. Asegúrate de utilizar los endpoints y respuestas adecuados al vincular el backend con el frontend del proyecto. </aside>

Después de crear las carpetas, archivos y respuestas, debes especificar los endpoints y sus respectivas rutas de archivos en el archivo index.yaml. Asegúrate de comenzar cada endpoint con ^/para indicar el inicio de la URL del endpoint. Utiliza las mismas rutas y nombres de archivos que definiste en el directorio stubby.

Aquí tienes un ejemplo de archivo index.yaml:

- request:
method: GET
url: ^/user/get-user
response:
headers:
content-type: application/json
file: ./get-user/data.json
- request:
method: POST
url: ^/user/create-new-user
headers:
content-type: application/json
response:
headers:
content-type: application/json
status: 200
file: ./create-new-user/data.json

#4 Crear los servicios

Ahora necesitamos llamar a los endpoints creados y utilizarlos en el proyecto. Si ya has completado esta parte, puedes omitirla y pasar al siguiente paso.

Para mantener el orden, es preferible crear carpetas específicas para los servicios, que son funciones que llaman a los endpoints utilizando el método fetch. Estos servicios se pueden utilizar en componentes o páginas.

En este caso, crearemos una carpeta llamada services dentro de la carpeta src, y dentro de ella, una carpeta llamada user con un archivoindex.js. Puedes elegir organizar tus funciones creando una carpeta para cada servicio o colocando todas las funciones relacionadas en un solo archivo. En mi caso, crearé un solo archivo que contenga todos los servicios relacionados con user.

Aquí tienes un ejemplo de estructura de directorios:

.
├── src
│ ├── components
│ ├── pages
│ ├── services
│ │ └── user
│ │ └── index.js
│ └── styles
├── stubby
│ ├── create-new-user
│ │ └── data.json
│ ├── get-user
│ │ └── data.json
│ └── index.yaml
├── README.md
├── jsconfig.json
├── next.config.js
├── package-lock.json
└── package.json

Lo siguiente es crear el archivo services/user/index.js y definir las funciones en las que llamaremos ambos endpoints. Estas funciones deberían coincidir con los endpoints reales ya creados ya sea en user como en el backend.

export const getUser = async (idUser) => {
try {
const url = `/user/get-user?id=${idUser}`;
const response = await fetch(url);
const data = await response.json();
return data;
} catch (error) {
console.error(error.message);
}
};

export const createNewUser = async (userData) => {
try {
const url = "/user/create-new-user";
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
const data = await response.json();
return data;
} catch (error) {
console.error(error.message);
}
};

En este ejemplo, utilizaremos estas funciones en un formulario. Cuando se envía el formulario, llamaremos al endpoint que crea un nuevo usuario en la base de datos (user/create-new-user. Si la respuesta tiene un código de estado 200, mostraremos un mensaje con la información del nuevo usuario utilizando el endpoint /user/get-user.

Aquí tienes un ejemplo de cómo usar estas funciones en el componente Home:

import { createNewUser, getUser } from '@/services/user';
import Head from 'next/head'
import { useState } from 'react';

const Home = () => {
const [form, setForm] = useState({});

const handleChangeInput = (e) => {
setForm({...form, [e.target.name]: e.target.value});
};

const createMessage = (isError, user) => {
return isError ? 'The user was succesfully created' :
`Hi! ${user.name} your user was succesfully created`
};

const getNewUser = async (idUser) => {
try {
const newUser = await getUser(idUser);
alert(createMessage(false, newUser));
}
catch (error) {
console.error(error.message);
return alert(createMessage(true, {}));
}

};

const handleRegisterSubmit = async (e) => {
e.preventDefault();
try {
const responseRegister = await createNewUser(form);
if(responseRegister.status == 200) getNewUser(responseRegister.user.id);
} catch {
alert('Something happened, please try again')
}
};

return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<form onSubmit={e => handleRegisterSubmit(e)}>
<div>
<label>Your name</label>
<input name='name' placeholder="John Smith" onChange={e => handleChangeInput(e)} />
</div>
<div>
<label>Your email</label>
<input name='email' placeholder="your_email@email.com" onChange={e => handleChangeInput(e)} />
</div>

<button type='submit'>Register</button>
</form>
</main>
</>
)
};

export default Home;

#5 Inicializar stubby

Ahora que todo ha sido creado, vamos a configurar el archivo package.json del proyecto para integrarlo con stubby.

Primero, necesitamos instalar la dependencia concurrently. Este paquete nos permite gestionar y ejecutar múltiples procesos simultáneamente sin necesidad de tener ventanas de terminal separadas. Nos ayudará a ejecutar tanto el servidor stubby para la simulación de la API como el servidor Next.js para nuestro código frontend en un solo comando.

Para instalar concurrently como una devDependecy, ejecuta el siguiente comando:

npm install concurrently --save-dev

Para mayores detalles puedes revisar la propia documentación de su página de npm.

Ahora vamos a actualizar el archivo package.json. Agrega los scripts dev:stubby y stubby junto a los scripts existentes de Next.js. El script dev:stubby ejecutará tanto el servidor stubby como el servidor de desarrollo de Next.js simultáneamente, mientras que el script stubby solo iniciará el servidor stubby.

Aquí tienes un ejemplo del archivo package.json actualizado:

{
"name": "example-stubby",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"dev:stubby": "concurrently --kill-others \\"npm run stubby\\" \\"npm run dev\\"",
"stubby": "stubby -w -d ./stubby/index.yaml -s 8815 -a 8816 -t 8817"
},
"dependencies": {
"next": "13.4.4",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"concurrently": "^8.2.0"
}
}

Déjame explicar el propósito de cada comando.

dev:stubby: Este script se utiliza para iniciar tanto el servidor stubby como el servidor de desarrollo de Next.js de forma paralela. Utiliza el paquete concurrently para ejecutar múltiples comandos en paralelo dentro de una única ventana de terminal.

npm run stubby: Este comando ejecuta el script stubby, que inicia el servidor stubby para simular APIs basado en las configuraciones especificadas en el archivo index.yaml.

npm run dev: Este comando inicia el servidor de desarrollo de Next.js, que ejecuta tu aplicación de Next.js.

Combinar estos dos comandos usando concurrentlyte permite ejecutar tanto el servidor stubby como el servidor Next.js simultáneamente, lo que te permite simular APIs mientras desarrollas tu aplicación frontend.

stubby: Este script inicia el servidor stubby de forma independiente sin ejecutar el servidor Next.js.

stubby -w -d ./stubby/index.yaml -s 8815 -a 8816 -t 8817: Este comando inicia el servidor stubby con las siguientes configuraciones:

  • w: Observa el archivo index.yaml en busca de cambios y recarga automáticamente el servidor cuando se producen cambios.
  • -d ./stubby/index.yaml: Especifica la ubicación del archivo YAML que contiene las configuraciones del servidor stubby.
  • -s 8815: Establece el puerto HTTP para el servidor stubby.
  • -a 8816: Establece el puerto HTTPS para el servidor stubby.
  • -t 8817: Establece el puerto del portal de administración de stubby.

Al ejecutar el script stubby solo, se inicia el servidor stubby, lo que te permite utilizarlo para simular APIs de forma independiente del servidor Next.js.

Estos scripts proporcionan comodidad y flexibilidad al ejecutar el servidor stubby y el servidor Next.js según tus necesidades específicas durante el desarrollo.

Si deseas verificar si stubby se inicializó correctamente, puedes usar npm run stubby. En la terminal, deberías ver algo como esto:

> example-stubby@0.1.0 stubby
> stubby -w -d ./stubby/index.yaml -s 8815 -a 8816 -t 8817
Loaded: GET ^/user/get-user
Loaded: POST ^/user/create-new-user
Watching for changes in ./stubby/index.yaml...
Quit: ctrl-c
Stubs portal running at <https://0.0.0.0:8817>
Stubs portal running at <http://0.0.0.0:8815>
Admin portal running at <http://0.0.0.0:8816>

Esto significa que stubby se está ejecutando en el portal http://0.0.0.0:8815. Si deseas llamar al endpoint que proporciona información del usuario, puedes verificar la URL http://0.0.0.0:8815/user/get-user. Debería devolver la siguiente respuesta y mostrarse en la página:

{
"name": "Anita",
"email": "Smith"
}

¡La mejor parte es que ahora puedes usar npm run dev:stubby para iniciar tanto el servidor stubby como el servidor de desarrollo de Next.js al mismo tiempo, lo que te permite probar tus endpoints de API mientras trabajas en tu proyecto de Next.js!

¡Pero falta algo! Si ejecutas la solución, completas el formulario y haces clic en el botón Register, se mostrará un mensaje de alerta indicando que algo salió mal. Si verificas la pestaña de red en la Consola de Desarrollo del navegador, verás que se muestra un código de estado 404 (No encontrado) para el endpoint create-new-user. La razón es que estamos llamando al endpoint http://localhost:3000/user/create-new-user, pero nuestro endpoint realmente está usando el puerto 8815. Por lo tanto, la URL correcta del endpoint debería ser http://0.0.0.0:8815/user/create-new-user.

Para solucionar este problema, debemos agregar una variable de entorno en el archivo .env e incluirla en la configuración de Next.js.

Actualiza el archivo .env con el siguiente contenido:

DEPLOY_ENVIRONMENT=local
BASE_URL=http://localhost:3000
LOCAL_PORT_BFF=8815

Luego, actualiza el archivo next.config.js. Esta configuración maneja tanto el entorno local como el de producción.

/** @type {import('next').NextConfig} */
const ENV = process.env.DEPLOY_ENVIRONMENT || 'local';
const LOCAL_PORT_BFF = process.env.LOCAL_PORT_BFF || 8080;
const getUrlsByEnvironment = {
local: {
BFF: `http://localhost:${LOCAL_PORT_BFF}`,
},
prod: {
BFF: '<https://www.url-backend.com>',
},
};
const nextConfig = {
reactStrictMode: true,
publicRuntimeConfig: {
...getUrlsByEnvironment[ENV]
}
}
module.exports = nextConfig

Con estas configuraciones, corre el comando npm run dev:stubby nuevamente, y verás ahora que los endpoints se llaman correctamente.

Recuerda que el archivo .env solo debe contener variables específicas del entorno local. Cuando implementes tu aplicación en plataformas como Vercel, deberás configurar las variables de entorno adecuadas para el entorno de producción.

Para obtener más información sobre las variables de entorno, puedes consultar la documentación de Vercel sobre variables de entorno.

PD: Si eres un hablante nativo en inglés o prefieres aprender estos conceptos usando el idioma más usado en equipos internacionales, puedes consultar la versión gemela de esta publicación. Mismos conceptos, mismas explicaciones, pero en diferente idioma 😉 cada semana.

--

--

Code & Cozy

Welcome to Code & Cozy, a tech blog where programming meets warmth and inspiration. Join us on a journey of learning and growth in the world of web development.