Cómo construir APIs REST escalables con Node.js y TypeScript

Aprende a diseñar APIs REST robustas y escalables usando Node.js y TypeScript. Incluye mejores prácticas, patrones de diseño y ejemplos prácticos.

Frontend
ReactTypeScriptUX

Cómo construir APIs REST escalables con Node.js y TypeScript

¿Tu empresa está lista para IA? Descargá nuestro checklist gratuito →

Descargar checklist

Introducción

En el desarrollo de software moderno, las APIs REST son el pilar de la comunicación entre servicios y aplicaciones. Node.js, con su modelo asíncrono y orientado a eventos, es una plataforma ideal para construir APIs de alto rendimiento. Al combinarlo con TypeScript, obtenemos tipado estático, mejor mantenibilidad y detección temprana de errores. En este artículo, exploraremos cómo construir APIs REST escalables utilizando Node.js y TypeScript, siguiendo patrones probados y buenas prácticas.

Configuración del proyecto

Primero, inicializamos el proyecto con npm init y agregamos las dependencias necesarias:

npm install express cors helmet morgan dotenv
npm install -D typescript @types/node @types/express @types/cors @types/morgan ts-node nodemon

Luego, creamos un tsconfig.json básico que compile a ES2020 y use CommonJS (o ESM si lo prefieres).

Estructura del proyecto

Una estructura limpia facilita la escalabilidad. Recomendamos:

src/
  controllers/
  services/
  repositories/
  middlewares/
  routes/
  utils/
  app.ts
  server.ts

Principios SOLID y separación de responsabilidades

Aplicar SOLID ayuda a mantener el código desacoplado y testable. Por ejemplo, separamos la lógica de negocio en servicios y el acceso a datos en repositorios.

Ejemplo de controlador con TypeScript:

import { Request, Response } from 'express';
import { UserService } from '../services/userService';

export class UserController {
  constructor(private userService: UserService) {}

  async getAll(req: Request, res: Response): Promise<void> {
    try {
      const users = await this.userService.findAll();
      res.json(users);
    } catch (error) {
      res.status(500).json({ message: 'Error al obtener usuarios' });
    }
  }
}

Manejo de errores centralizado

Un middleware de errores uniforme facilita el debugging y la experiencia del cliente.

// middlewares/errorHandler.ts
import { Request, Response, NextFunction } from 'express';

export class AppError extends Error {
  statusCode: number;
  constructor(message: string, statusCode: number) {
    super(message);
    this.statusCode = statusCode;
  }
}

export const errorHandler = (
  err: Error,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  if (err instanceof AppError) {
    return res.status(err.statusCode).json({ error: err.message });
  }
  console.error(err);
  res.status(500).json({ error: 'Error interno del servidor' });
};

Validación de datos con Zod

Zod es una librería de validación que se integra perfectamente con TypeScript.

¿Querés un diagnóstico personalizado? Completá el checklist gratuito →

Descargar checklist
import { z } from 'zod';

export const createUserSchema = z.object({
  name: z.string().min(3),
  email: z.string().email(),
  age: z.number().positive().optional(),
});

type CreateUserInput = z.infer<typeof createUserSchema>;

Paginación y filtros escalables

Para evitar sobrecargar el servidor, implementa paginación con offset/limit o cursor-based. Ejemplo:

// services/userService.ts
async findAll(page: number = 1, limit: number = 10) {
  const skip = (page - 1) * limit;
  return await this.userRepository.findMany(skip, limit);
}

Uso de middlewares de seguridad

  • Helmet para proteger contra vulnerabilidades web.
  • CORS configurado adecuadamente.
  • Rate limiting con express-rate-limit.
import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutos
  max: 100, // límite de 100 peticiones por ventana
  message: 'Demasiadas peticiones, intente más tarde',
});

app.use(limiter);

Inyección de dependencias con tsyringe

Para un acoplamiento más débil, podemos usar un contenedor de DI como tsyringe:

import { container } from 'tsyringe';
import { UserService } from './services/userService';
import { UserRepository } from './repositories/userRepository';

container.registerSingleton(UserRepository);
container.registerSingleton(UserService);

// En el controlador
const userService = container.resolve(UserService);

Pruebas unitarias y de integración

TypeScript facilita escribir pruebas con Jest y Supertest. Ejemplo de prueba para un controlador:

import request from 'supertest';
import app from '../app';

describe('GET /api/users', () => {
  it('debería devolver lista de usuarios', async () => {
    const res = await request(app).get('/api/users');
    expect(res.status).toBe(200);
    expect(Array.isArray(res.body)).toBeTruthy();
  });
});

Documentación con Swagger

Integrar Swagger permite que otros desarrolladores consuman tu API fácilmente.

npm install swagger-jsdoc swagger-ui-express
import swaggerJsDoc from 'swagger-jsdoc';
import swaggerUi from 'swagger-ui-express';

const swaggerOptions = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'API de Usuarios',
      version: '1.0.0',
    },
  },
  apis: ['./src/routes/*.ts'],
};

const swaggerDocs = swaggerJsDoc(swaggerOptions);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs));

Despliegue escalable

Para producción, considera:

  • Compilar TypeScript a JavaScript con tsc.
  • Usar un gestor de procesos como PM2.
  • Contenerizar con Docker.
  • Balanceo de carga con Nginx.

Ejemplo de Dockerfile:

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist/ ./
EXPOSE 3000
CMD ["node", "server.js"]

Conclusión

Construir APIs REST escalables con Node.js y TypeScript no solo mejora la productividad, sino que también asegura un código más robusto y mantenible. Aplicando patrones como separación de responsabilidades, validación con Zod, manejo centralizado de errores y pruebas automatizadas, puedes enfrentar desafíos de crecimiento sin perder calidad.

Para profundizar, te recomiendo leer la guía oficial de Express sobre mejores prácticas y el artículo de Node.js sobre escalabilidad.

¡Empieza hoy y construye APIs que escalen!

¿Listo para dar el próximo paso? Evaluá tu empresa con nuestro checklist gratuito →

Descargar checklist

Publicaciones relacionadas