Introducción: ¿Por qué TypeScript para REST API?
El desarrollo web moderno es impensable sin APIs claras y escalables. TypeScript, siendo un superconjunto fuertemente tipado de JavaScript, permite crear REST APIs robustas con un mínimo de errores en tiempo de ejecución. En este artículo, de forma práctica y paso a paso, crearemos una REST API completa en TypeScript utilizando el popular framework Express. Todo el proceso te llevará no más de 30 minutos, y el resultado estará listo para usar en proyectos reales.
Abordaremos: inicialización del proyecto, configuración de TypeScript, creación de rutas, trabajo con middleware, manejo de errores y prueba de endpoints. Todos los ejemplos de código podrás ejecutarlos inmediatamente y adaptarlos a tus necesidades.
Paso 1: Inicialización del proyecto e instalación de dependencias
Primero, crearemos un nuevo directorio para el proyecto y lo inicializaremos. Abre la terminal y ejecuta:
mkdir my-ts-api
cd my-ts-api
npm init -y
Ahora instalaremos los paquetes necesarios:
npm install express
npm install -D typescript @types/node @types/express ts-node nodemon
Crearemos el archivo de configuración de TypeScript:
npx tsc --init
Edita tsconfig.json incluyendo las siguientes opciones:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
}
}
Añade los scripts en package.json:
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "nodemon --exec ts-node src/index.ts"
}
Paso 2: Creación de la estructura base y el primer endpoint
Crea la carpeta src y dentro de ella el archivo index.ts. Comenzaremos con un servidor simple que responda a peticiones GET:
import express, { Request, Response } from 'express';
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware para parsear JSON
app.use(express.json());
// Ruta base
app.get('/', (req: Request, res: Response) => {
res.send('¡REST API en TypeScript funcionando!');
});
app.listen(PORT, () => {
console.log(`Servidor iniciado en http://localhost:${PORT}`);
});
Ejecuta el servidor con el comando npm run dev y abre http://localhost:3000. Verás el mensaje de bienvenida.
Creación del modelo de datos
Para una API completa necesitamos una entidad. Crearemos un modelo simple de usuario:
// src/models/user.ts
export interface User {
id: number;
name: string;
email: string;
age: number;
}
export type CreateUserDto = Omit;
Paso 3: Implementación de operaciones CRUD
Ahora crearemos un controlador y rutas para trabajar con usuarios. Crea el archivo src/routes/users.ts:
import { Router, Request, Response } from 'express';
import { User, CreateUserDto } from '../models/user';
const router = Router();
let users: User[] = [
{ id: 1, name: 'Iván', email: 'ivan@example.com', age: 28 },
{ id: 2, name: 'María', email: 'maria@example.com', age: 32 }
];
let nextId = 3;
// GET /users - obtener todos los usuarios
router.get('/', (req: Request, res: Response) => {
res.json(users);
});
// GET /users/:id - obtener un usuario por ID
router.get('/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const user = users.find(u => u.id === id);
if (!user) {
return res.status(404).json({ message: 'Usuario no encontrado' });
}
res.json(user);
});
// POST /users - crear un nuevo usuario
router.post('/', (req: Request, res: Response) => {
const { name, email, age }: CreateUserDto = req.body;
if (!name || !email || !age) {
return res.status(400).json({ message: 'Faltan campos requeridos' });
}
const newUser: User = { id: nextId++, name, email, age };
users.push(newUser);
res.status(201).json(newUser);
});
// PUT /users/:id - actualizar un usuario existente
router.put('/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const index = users.findIndex(u => u.id === id);
if (index === -1) {
return res.status(404).json({ message: 'Usuario no encontrado' });
}
const { name, email, age }: CreateUserDto = req.body;
users[index] = { ...users[index], name, email, age };
res.json(users[index]);
});
// DELETE /users/:id - eliminar un usuario
router.delete('/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const index = users.findIndex(u => u.id === id);
if (index === -1) {
return res.status(404).json({ message: 'Usuario no encontrado' });
}
users.splice(index, 1);
res.status(204).send();
});
export default router;
Paso 4: Conexión de rutas y middleware de errores
Actualiza src/index.ts para usar las rutas de usuarios y añadir manejo de errores:
import express, { Request, Response, NextFunction } from 'express';
import userRoutes from './routes/users';
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
// Rutas
app.use('/users', userRoutes);
// Middleware de manejo de errores
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error(err.stack);
res.status(500).json({ message: 'Error interno del servidor' });
});
app.listen(PORT, () => {
console.log(`Servidor iniciado en http://localhost:${PORT}`);
});
Paso 5: Prueba de la API
Ahora puedes probar todos los endpoints. Aquí tienes algunos ejemplos con curl:
# Obtener todos los usuarios
curl http://localhost:3000/users
# Obtener un usuario por ID
curl http://localhost:3000/users/1
# Crear un nuevo usuario
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name":"Pedro","email":"pedro@example.com","age":25}'
# Actualizar un usuario
curl -X PUT http://localhost:3000/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"Iván Actualizado","email":"ivan.nuevo@example.com","age":29}'
# Eliminar un usuario
curl -X DELETE http://localhost:3000/users/1
Conclusión
Has creado con éxito una REST API completa en TypeScript usando Express. Has aprendido a:
- Configurar un proyecto TypeScript con Express
- Crear modelos de datos tipados
- Implementar operaciones CRUD completas
- Manejar errores de forma profesional
- Probar los endpoints de la API
Esta base es fácilmente extensible: puedes añadir autenticación, conectar una base de datos, agregar validación con librerías como Zod o Joi, y mucho más. TypeScript te proporciona la seguridad de tipos que necesitas para que tu API sea fiable y mantenible a largo plazo.