Cómo Crear APIs Backend con NitroJs

Ashley Goolam

Ashley Goolam

19 January 2026

Cómo Crear APIs Backend con NitroJs

Cuando construí mi primera API de producción, utilicé Express.js y la configuración me llevó unas dos horas: código repetitivo, middleware, manejadores de rutas, configuración de TypeScript y scripts de despliegue. Recientemente, lancé una API REST completa en solo 20 minutos usando NitroJs. Sin cadenas de app.use(), sin enrutamiento manual, sin dolores de cabeza de despliegue.

Esta guía te muestra cómo NitroJs elimina el código repetitivo a la vez que te proporciona un backend listo para producción que se ejecuta en cualquier lugar: Node, Bun, Deno, sin servidor o en el edge.

¿Qué es NitroJs y por qué usarlo para APIs de Backend?

NitroJs es un kit de herramientas de servidor del ecosistema UnJS que trata tu backend como un artefacto de construcción. En lugar de escribir un servidor que se acople a un tiempo de ejecución, escribes manejadores de rutas y Nitro los compila en un paquete portátil. Despliega el mismo código en Node.js, Cloudflare Workers, Vercel o un contenedor Docker sin cambiar una sola línea.

NitroJs para APIs de Backend

Modelo mental central: Escribe rutas, no servidores. Te centras en la lógica de la API; Nitro maneja HTTP, el middleware y el pegamento de la plataforma.

Ventajas clave para APIs de backend:

Para los desarrolladores de API, esto significa que lanzas más rápido y refactorizas menos al cambiar de infraestructura.

botón

Primeros Pasos: Instala NitroJs en 5 Minutos

Paso 1: Crear un Proyecto

# Usando pnpm (recomendado)
pnpm dlx giget@latest nitro nitro-api-backend

# O npm
npm create nitro@latest nitro-api-backend

# O bun
bunx giget@latest nitro nitro-api-backend

Esto clona la plantilla inicial oficial en nitro-api-backend.

Paso 2: Explorar la Estructura

cd nitro-api-backend
tree -L 2

Salida:

├── server
│   ├── api
│   ├── routes
│   ├── tasks
│   └── middleware
├── nitro.config.ts
├── package.json
└── tsconfig.json

Directorios críticos:

Para una API de backend pura, ignora routes y pon todo en api.

Paso 3: Ejecutar el Servidor de Desarrollo

pnpm install
pnpm dev

Nitro se inicia en http://localhost:3000 con recarga en caliente. Edita un archivo y el servidor se reinicia en menos de 200ms.

Primeros pasos con NitroJs

Construyendo tu Primer Endpoint de API

Manejador GET Simple

Crea server/api/users.get.ts:

// server/api/users.get.ts
export default defineEventHandler(() => {
  return [
    { id: 1, name: "Alice", email: "alice@example.com" },
    { id: 2, name: "Bob", email: "bob@example.com" }
  ];
});

Nitro sirve esto automáticamente en GET /api/users. El envoltorio defineEventHandler proporciona seguridad de tipos y acceso al contexto de la solicitud.

Ruta Dinámica con Parámetros

Crea server/api/users/[id].get.ts:

// server/api/users/[id].get.ts
export default defineEventHandler((event) => {
  const id = getRouterParam(event, 'id');
  
  if (!id) {
    throw createError({
      statusCode: 400,
      statusMessage: 'User ID is required'
    });
  }
  
  return {
    id: Number(id),
    name: `User ${id}`,
    email: `user${id}@example.com`
  };
});

Accede a GET /api/users/42 para ver { id: 42, name: "User 42", ... }.

POST con Cuerpo JSON

Crea server/api/users.post.ts:

// server/api/users.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event);
  
  // Nitro parsea JSON automáticamente
  const { name, email } = body;
  
  if (!name || !email) {
    throw createError({
      statusCode: 422,
      statusMessage: 'Name and email are required'
    });
  }
  
  // Simular inserción en la base de datos
  const newUser = {
    id: Math.floor(Math.random() * 1000),
    name,
    email,
    createdAt: new Date().toISOString()
  };
  
  return newUser;
});

Pruébalo:

curl -X POST http://localhost:3000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"Charlie","email":"charlie@example.com"}'

Respuestas con Seguridad de Tipos

Nitro infiere los tipos de respuesta de tus valores de retorno. Para contratos estrictos, usa tipos explícitos:

// server/api/products.get.ts
interface Product {
  id: number;
  name: string;
  price: number;
  inStock: boolean;
}

export default defineEventHandler<Product[]>(() => {
  return [
    { id: 1, name: "Laptop", price: 1299.99, inStock: true },
    { id: 2, name: "Mouse", price: 29.99, inStock: false }
  ];
});

Ahora, los clientes que importan este endpoint obtienen IntelliSense completo.

Patrones Avanzados de API

Middleware para Autenticación

Crea server/middleware/auth.ts:

// server/middleware/auth.ts
export default defineEventHandler(async (event) => {
  const protectedRoutes = ['/api/admin', '/api/users/me'];
  
  if (protectedRoutes.some(route => event.path.startsWith(route))) {
    const token = getHeader(event, 'authorization')?.replace('Bearer ', '');
    
    if (!token || token !== process.env.API_SECRET) {
      throw createError({
        statusCode: 401,
        statusMessage: 'Unauthorized'
      });
    }
  }
});

El middleware se ejecuta antes de cada ruta. Agrégalo a nitro.config.ts:

// nitro.config.ts
export default defineNitroConfig({
  srcDir: 'server',
  runtimeConfig: {
    apiSecret: process.env.API_SECRET
  }
});

Almacenamiento en Caché de Respuestas de API

Almacena en caché cálculos costosos durante 60 segundos:

// server/api/stats.get.ts
export default defineCachedEventHandler(async () => {
  const db = useStorage('data');
  const users = await db.getItem('users') || [];
  
  return {
    totalUsers: users.length,
    activeUsers: users.filter(u => u.lastSeen > Date.now() - 86400000).length
  };
}, {
  maxAge: 60, // segundos
  name: 'stats',
  getKey: () => 'global-stats'
});

Nitro maneja la invalidación y el almacenamiento de caché (memoria, Redis o Cloudflare KV según el destino del despliegue).

Manejo de Carga de Archivos

// server/api/upload.post.ts
export default defineEventHandler(async (event) => {
  const files = await readMultipartFormData(event);
  
  if (!files?.length) {
    throw createError({ statusCode: 400, statusMessage: 'No files uploaded' });
  }
  
  const storage = useStorage('uploads');
  const file = files[0];
  
  await storage.setItem(file.filename, file.data);
  
  return { success: true, filename: file.filename };
});

Prueba con:

curl -X POST http://localhost:3000/api/upload \
  -F "file=@/ruta/a/imagen.jpg"

Despliegue: De Local a Producción

Construcción para Producción

pnpm build

Nitro genera un directorio .output con puntos de entrada específicos de la plataforma.

Ejecutar en Node.js

node .output/server/index.mjs

No se requieren node_modules—la construcción empaqueta todo.

Desplegar en Cloudflare Workers

# Instalar preset
pnpm add -D nitro-preset-cloudflare-workers

# Construir con preset
NITRO_PRESET=cloudflare-workers pnpm build

# Desplegar
wrangler deploy .output

Desplegar en Vercel (Serverless)

# Vercel detecta Nitro automáticamente
vercel

O configura nitro.config.ts:

export default defineNitroConfig({
  preset: 'vercel-edge'
});

Variables de Entorno

Crea .env localmente, luego usa los paneles de la plataforma en producción:

# .env
API_SECRET=dev-secret-key
DATABASE_URL=file:./dev.db

Acceder en los manejadores:

const config = useRuntimeConfig();
const secret = config.apiSecret;

Casos de Uso Avanzados

WebSockets y Eventos Enviados por el Servidor

Nitro soporta WebSockets a través de defineWebSocketHandler:

// server/api/ws.ts
export default defineWebSocketHandler({
  open(peer) {
    console.log('WebSocket conectado:', peer);
  },
  message(peer, message) {
    peer.send(`Eco: ${message.text()}`);
  },
  close(peer, details) {
    console.log('WebSocket cerrado:', details);
  }
});

Accede en ws://localhost:3000/api/ws.

Tareas en Segundo Plano

Crea server/tasks/cleanup.ts:

// server/tasks/cleanup.ts
export default defineCronHandler('0 2 * * *', async () => {
  const db = useStorage('temp');
  const keys = await db.getKeys();
  
  for (const key of keys) {
    const metadata = await db.getMeta(key);
    if (metadata.expiresAt < Date.now()) {
      await db.removeItem(key);
    }
  }
  
  console.log('Limpieza completada');
});

Esto se ejecuta diariamente a las 2 AM. Despliega en una plataforma con soporte cron (ej. Vercel, Netlify).

Motores de Flujo de Trabajo

Integra con useWorkflow.dev para orquestación compleja:

// server/api/workflows/process.ts
import { createWorkflow } from '@useworkflow/sdk';

export default defineEventHandler(async (event) => {
  const workflow = createWorkflow('data-pipeline', {
    steps: [
      { id: 'fetch', run: 'https://api.example.com/data' },
      { id: 'transform', run: 'transform.js' },
      { id: 'store', run: async (data) => {
        const storage = useStorage('results');
        await storage.setItem('latest', data);
      }}
    ]
  });
  
  await workflow.start();
  return { status: 'iniciado' };
});

Escenarios Reales para Desarrolladores

Escenario 1: Backend de Sitio Estático

Despliega una API de Nitro en Cloudflare Workers que sirva datos JSON a un sitio estático JAMstack. El nivel gratuito maneja 100K solicitudes/día.

Escenario 2: API de Aplicación Móvil

Construye endpoints REST para una aplicación React Native. Usa el manejo CORS integrado de Nitro:

// nitro.config.ts
export default defineNitroConfig({
  routeRules: {
    '/api/**': { cors: true }
  }
});

Escenario 3: Pasarela de Microservicios

Ejecuta Nitro como una pasarela de API que agrega microservicios. Usa $fetch para proxy de solicitudes:

// server/api/aggregate.get.ts
export default defineEventHandler(async (event) => {
  const [users, posts] = await Promise.all([
    $fetch('https://users-service.internal/users'),
    $fetch('https://posts-service.internal/posts')
  ]);
  
  return { users, posts };
});

Prueba tus APIs de NitroJs con Apidog

Nitro genera backends rápidamente, pero la velocidad no significa nada si tus endpoints fallan. Cuando lanzas un nuevo POST /api/users, importa la definición de la ruta en Apidog. Ingenia inversamente el tipo de retorno de tu manejador y genera pruebas de contrato automáticamente.

Pruebas de Contrato de API con Apidog
botón

Ejecútalos en CI para detectar cambios que puedan romper antes de que tu equipo de frontend se arranque los pelos. Es gratis para empezar, y es la salvaguarda que necesita tu rápido desarrollo con Nitro.

Preguntas Frecuentes

1. ¿Puede Nitro reemplazar a Express.js por completo?
Sí. Nitro maneja el enrutamiento, el middleware y el despliegue mejor. Migra moviendo el middleware de Express a los plugins de Nitro y las rutas a server/api/.

2. ¿Cómo maneja Nitro las conexiones a la base de datos?
Usa los plugins de Nitro para inicializar pools al inicio. La capa de almacenamiento abstrae el almacenamiento en caché, pero para SQL, usa tu propio ORM (Prisma, Drizzle).

3. ¿Está Nitro listo para producción?
Absolutamente. Nuxt usa Nitro para millones de sitios en producción. Está probado en batalla para escalar.

4. ¿Puedo usar Nitro con GraphQL?
Sí. Agrega un manejador GraphQL en server/api/graphql.post.ts. Usa cualquier librería de GraphQL de Node—Nitro no te restringe.

5. ¿Cuál es la diferencia entre Nitro y Hono?
Hono es un enrutador ligero. Nitro es un kit de herramientas de servidor completo con compilaciones, presets y almacenamiento. Usa Hono para microservicios, Nitro para backends completos.

Conclusión

NitroJs replantea el desarrollo de backend compilando tu API en un artefacto portátil. Obtienes enrutamiento por sistema de archivos, seguridad de tipos de TypeScript y despliegue universal sin código repetitivo. Construye tu próxima API REST con Nitro, y valídala con Apidog. Tu yo futuro te lo agradecerá cuando migres de Node al edge en una sola línea de configuración.

botón

Practica el diseño de API en Apidog

Descubre una forma más fácil de construir y usar APIs