Cómo escribir una API REST en TypeScript en 30 minutos: en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: por qué TypeScript y REST API son la pareja ideal para el desarrollo rápido

\n

El desarrollo web moderno exige velocidad y fiabilidad. Si necesita crear rápidamente un backend para una aplicación móvil, un servicio web o una arquitectura de microservicios, la combinación TypeScript + Node.js + Express es una de las herramientas más eficaces. TypeScript añade tipado estricto a JavaScript, lo que permite detectar errores en la fase de compilación, no en tiempo de ejecución. Esto es especialmente valioso al construir una API REST, donde cada endpoint debe saber con claridad qué datos recibe y devuelve.

\n

En este artículo, crearemos en 30 minutos una API REST completa para gestionar una lista de tareas (To-Do List). Aprenderá a configurar el proyecto, escribir controladores, rutas y middleware. Todo con ejemplos prácticos y código listo para usar.

\n\n

Preparación y configuración del proyecto (5 minutos)

\n

Primero, crearemos la estructura del proyecto e instalaremos las dependencias.

\n
mkdir todo-api\ncd todo-api\nnpm init -y\nnpm install express cors uuid\nnpm install -D typescript @types/express @types/cors @types/uuid ts-node nodemon
\n

Cree el archivo tsconfig.json en la raíz del proyecto:

\n
{\n  "compilerOptions": {\n    "target": "ES2020",\n    "module": "commonjs",\n    "outDir": "./dist",\n    "rootDir": "./src",\n    "strict": true,\n    "esModuleInterop": true,\n    "skipLibCheck": true\n  },\n  "include": ["src/**/*"]\n}
\n

Agregue los scripts en package.json:

\n
"scripts": {\n  "dev": "nodemon --exec ts-node src/index.ts",\n  "build": "tsc",\n  "start": "node dist/index.js"\n}
\n

Cree la carpeta src y el archivo index.ts — el punto de entrada.

\n\n

Estructura básica de carpetas

\n
    \n
  • src/index.ts — punto de entrada, inicio del servidor
  • \n
  • src/routes/tasks.ts — rutas para las tareas
  • \n
  • src/controllers/taskController.ts — lógica de procesamiento de solicitudes
  • \n
  • src/models/task.ts — interfaces y tipos
  • \n
  • src/middleware/errorHandler.ts — manejo de errores (opcional)
  • \n
\n\n

Creación del modelo de datos e interfaces (5 minutos)

\n

Definamos los tipos de datos para nuestra tarea. Cree el archivo src/models/task.ts:

\n
export interface Task {\n  id: string;\n  title: string;\n  completed: boolean;\n  createdAt: Date;\n}\n\nexport type CreateTaskDto = Pick<Task, 'title'>;\nexport type UpdateTaskDto = Partial<Pick<Task, 'title' | 'completed'>>;
\n

Aquí usamos Pick y Partial — tipos utilitarios incorporados de TypeScript. CreateTaskDto acepta solo el título, mientras que UpdateTaskDto acepta campos opcionales para una actualización parcial.

\n\n

Escritura de controladores y rutas (15 minutos)

\n

Ahora viene lo más interesante: la lógica de la aplicación. Crearemos un almacenamiento temporal de tareas en memoria (in-memory storage). Para producción, debe reemplazarse por una base de datos.

\n\n

Controlador de tareas

\n

Archivo src/controllers/taskController.ts:

\n
import { Request, Response } from 'express';\nimport { v4 as uuidv4 } from 'uuid';\nimport { Task, CreateTaskDto, UpdateTaskDto } from '../models/task';\n\n// Almacenamiento temporal\nlet tasks: Task[] = [];\n\n// GET /api/tasks\nexport const getAllTasks = (req: Request, res: Response) => {\n  res.json(tasks);\n};\n\n// GET /api/tasks/:id\nexport const getTaskById = (req: Request, res: Response) => {\n  const task = tasks.find(t => t.id === req.params.id);\n  if (!task) {\n    return res.status(404).json({ message: 'Tarea no encontrada' });\n  }\n  res.json(task);\n};\n\n// POST /api/tasks\nexport const createTask = (req: Request, res: Response) => {\n  const { title } = req.body as CreateTaskDto;\n  if (!title || typeof title !== 'string') {\n    return res.status(400).json({ message: 'El campo title es obligatorio y debe ser una cadena' });\n  }\n                

Blogs

Book Recommendations