En pocas palabras
Framework web de Node.js para crear APIs y servicios con bajo costo de procesamiento, validación por esquemas y plugins encapsulados.
Qué problema resuelve
Trabajo repetitivo de rutas, validación, serialización y registro de eventos al construir servicios HTTP.
Cuándo utilizarlo
APIs JSON, microservicios y backends en JavaScript o TypeScript. Ejemplo: publicar un endpoint cuyo esquema valida la petición y controla la serialización de la respuesta.
De la idea a la práctica
Funcionamiento, ejemplos y decisiones para pasar al siguiente nivel.
Cómo funciona
Fastify organiza rutas, hooks y plugins. Los esquemas permiten validar entradas y compilar la serialización de respuestas. La encapsulación ayuda a delimitar el alcance de configuraciones y extensiones.
Ejemplo: un servicio mínimo
Con fastify instalado y un proyecto configurado como módulo ES:
import Fastify from 'fastify';
const app = Fastify({ logger: true });
app.get('/salud', async () => ({ ok: true }));
await app.listen({ port: 3000, host: '127.0.0.1' });
Ruta con esquema de entrada y salida
app.post(
'/v1/solicitudes',
{
schema: {
body: {
type: 'object',
required: ['documento', 'monto', 'plazo'],
additionalProperties: false,
properties: {
documento: { type: 'string', pattern: '^[0-9]{6,10}$' },
monto: { type: 'number', minimum: 100000 },
plazo: { type: 'integer', minimum: 3, maximum: 60 },
},
},
response: {
202: {
type: 'object',
properties: { id: { type: 'string' }, estado: { type: 'string' } },
},
},
},
},
async (request, reply) => {
const solicitud = await app.solicitudes.crear(request.body);
return reply.code(202).send(solicitud);
},
);
El esquema de respuesta no solo acelera la serialización: impide filtrar campos no declarados (por ejemplo, datos internos que vengan del repositorio). Con un type provider como TypeBox o Zod, los tipos de TypeScript se derivan del mismo esquema.
Plugins y encapsulación
// plugins/db.js — compartido con toda la app gracias a fastify-plugin
import fp from 'fastify-plugin';
export default fp(async (app) => {
const pool = crearPool(process.env.DATABASE_URL);
app.decorate('db', pool);
app.addHook('onClose', async () => pool.end());
});
// rutas/admin.js — hooks que solo afectan a este contexto
export default async (app) => {
app.addHook('onRequest', app.verificarRol('admin'));
app.get('/usuarios', async () => app.db.query('SELECT …'));
};
app.register(db);
app.register(admin, { prefix: '/admin' });
Sin fastify-plugin, lo que registra un plugin queda encapsulado en su contexto: es la forma de aislar módulos.
Ciclo de vida de una petición
onRequest → preParsing → preValidation → validación → preHandler → handler → preSerialization → onSend → onResponse. Autenticación en onRequest, autorización por recurso en preHandler.
Plugins habituales
| Plugin | Para qué |
|---|---|
@fastify/helmet |
Cabeceras de seguridad |
@fastify/rate-limit |
Límite de peticiones |
@fastify/cors |
CORS |
@fastify/jwt |
Autenticación con JWT |
@fastify/swagger |
OpenAPI generado desde los esquemas |
@fastify/under-pressure |
Rechazar carga cuando el proceso se satura |
Pruebas sin levantar el servidor
const res = await app.inject({
method: 'POST',
url: '/v1/solicitudes',
payload: { documento: '123' },
});
assert.equal(res.statusCode, 400);
inject ejecuta toda la cadena de hooks y validación en memoria, ideal para pruebas rápidas. El logger integrado es Pino (JSON estructurado), que encaja con Grafana Loki u OpenTelemetry.
Criterios de implementación
Añade esquemas a las rutas públicas y separa plugins por responsabilidad. Integra gestión de errores, límites de petición y apagado ordenado. Mide rendimiento con las dependencias reales; un endpoint vacío no representa una aplicación completa.
Continúa en las fuentes
Documentación oficial para verificar detalles y explorar más.