REST API

CONCEPTSIntermedio
⏱️ 5 min de lectura🏷️ api, architecture, web-services

REST API

REST API (Representational State Transfer) es un estilo arquitectónico para diseñar servicios web que utiliza HTTP de manera estandardizada.

¿Qué es REST API?

Imagina que una API es como un menú de restaurante que te permite pedir comida, entonces REST API es un menú muy bien organizado donde cada plato tiene un nombre claro, precio especificado, y instrucciones precisas sobre cómo pedirlo.

REST (Representational State Transfer) es un estilo arquitectónico que define reglas claras sobre cómo diseñar APIs web. Es como tener un manual de buenas prácticas que hace que las APIs sean predecibles, organizadas y fáciles de usar.

REST API te da:

  • URLs organizadas y lógicas - Como /usuarios/123/pedidos para ver pedidos del usuario 123
  • Métodos HTTP claros - GET para obtener, POST para crear, PUT para actualizar, DELETE para eliminar
  • Sin dependencias entre peticiones - Cada petición es independiente, como ordenar platos por separado
  • Respuestas consistentes - Siempre sabes qué formato esperar
  • Fácil de cachear - Las respuestas se pueden guardar temporalmente para ser más rápido

REST se volvió el estándar porque hace que trabajar con APIs sea intuitivo: si sabes cómo usar una API REST, puedes entender fácilmente otra API REST diferente.

Principios REST

1. Recursos

Todo en REST es un recurso identificado por una URL:

Usuarios:     /api/usuarios
Usuario:      /api/usuarios/123
Posts:        /api/usuarios/123/posts
Post:         /api/usuarios/123/posts/456

2. Métodos HTTP

Usar métodos HTTP para diferentes acciones:

GET     → Leer/Obtener
POST    → Crear
PUT     → Actualizar completo
PATCH   → Actualizar parcial
DELETE  → Eliminar

3. Representaciones

Los recursos se representan en diferentes formatos:

JSON    → application/json
XML     → application/xml
HTML    → text/html

4. Sin Estado

Cada petición debe contener toda la información necesaria:

# ✓ Bueno: Incluye autenticación
GET /api/usuarios/123 HTTP/1.1
Authorization: Bearer token123

# ✗ Malo: Depende del estado de sesión
GET /api/usuarios/123 HTTP/1.1
# Asume que ya se inició sesión

Diseño de URLs REST

Estructura Básica

# Colección de recursos
GET    /api/usuarios              # Listar usuarios
POST   /api/usuarios              # Crear usuario

# Recurso individual
GET    /api/usuarios/123          # Obtener usuario 123
PUT    /api/usuarios/123          # Actualizar usuario 123
PATCH  /api/usuarios/123          # Actualizar parcialmente
DELETE /api/usuarios/123          # Eliminar usuario 123

Recursos Anidados

# Posts de un usuario
GET    /api/usuarios/123/posts    # Posts del usuario 123
POST   /api/usuarios/123/posts    # Crear post para usuario 123

# Post específico
GET    /api/usuarios/123/posts/456  # Post 456 del usuario 123
PUT    /api/usuarios/123/posts/456  # Actualizar post 456
DELETE /api/usuarios/123/posts/456  # Eliminar post 456

Parámetros de Consulta

# Filtrado
GET /api/usuarios?activo=true
GET /api/usuarios?rol=admin

# Paginación
GET /api/usuarios?page=2&limit=10
GET /api/usuarios?offset=20&limit=10

# Ordenamiento
GET /api/usuarios?sort=nombre&order=asc
GET /api/usuarios?sort=-fechaCreacion  # - para descendente

# Búsqueda
GET /api/usuarios?q=juan
GET /api/usuarios?search=desarrollador

# Inclusión de relaciones
GET /api/usuarios/123?include=posts,profile

# Selección de campos
GET /api/usuarios?fields=id,nombre,email

Ejemplos de API REST

Obtener Lista de Usuarios

Petición:

GET /api/usuarios?page=1&limit=5 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJ0eXAiOiJKV1Q...

Respuesta:

HTTP/1.1 200 OK
Content-Type: application/json
X-Total-Count: 150
X-Page: 1
X-Per-Page: 5

{
  "data": [
    {
      "id": 1,
      "nombre": "Ana García",
      "email": "[email protected]",
      "fechaCreacion": "2023-01-15T10:30:00Z"
    },
    {
      "id": 2,
      "nombre": "Carlos López",
      "email": "[email protected]",
      "fechaCreacion": "2023-01-16T14:22:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "perPage": 5,
    "total": 150,
    "totalPages": 30
  },
  "links": {
    "self": "/api/usuarios?page=1&limit=5",
    "next": "/api/usuarios?page=2&limit=5",
    "last": "/api/usuarios?page=30&limit=5"
  }
}

Crear Usuario

Petición:

POST /api/usuarios HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJ0eXAiOiJKV1Q...

{
  "nombre": "Juan Pérez",
  "email": "[email protected]",
  "password": "secreto123",
  "rol": "usuario"
}

Respuesta:

HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/usuarios/151

{
  "id": 151,
  "nombre": "Juan Pérez",
  "email": "[email protected]",
  "rol": "usuario",
  "fechaCreacion": "2023-07-27T12:28:53Z",
  "fechaActualizacion": "2023-07-27T12:28:53Z"
}

Actualizar Usuario

Petición:

PATCH /api/usuarios/151 HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJ0eXAiOiJKV1Q...

{
  "nombre": "Juan Pérez Actualizado"
}

Respuesta:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 151,
  "nombre": "Juan Pérez Actualizado",
  "email": "[email protected]",
  "rol": "usuario",
  "fechaCreacion": "2023-07-27T12:28:53Z",
  "fechaActualizacion": "2023-07-27T13:45:12Z"
}

Manejo de Errores

Usuario No Encontrado:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "El usuario con ID 999 no existe",
    "details": {
      "resource": "usuarios",
      "id": 999
    }
  }
}

Error de Validación:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Los datos proporcionados no son válidos",
    "fields": {
      "email": ["El email ya está en uso"],
      "password": ["La contraseña debe tener al menos 8 caracteres"]
    }
  }
}

Versionado de APIs

En la URL

GET /api/v1/usuarios
GET /api/v2/usuarios

En Headers

GET /api/usuarios HTTP/1.1
API-Version: 2
# o
Accept: application/vnd.api+json;version=2

En Parámetros

GET /api/usuarios?version=2

Autenticación y Autorización

JWT Token

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...

API Key

X-API-Key: tu-api-key-secreta
# o en parámetros
GET /api/usuarios?api_key=tu-api-key

OAuth 2.0

Authorization: Bearer oauth-access-token

Mejores Prácticas

1. Usar Sustantivos, No Verbos

✓ GET /api/usuarios
✗ GET /api/obtenerUsuarios

✓ POST /api/usuarios
✗ POST /api/crearUsuario

2. Plurales para Colecciones

✓ /api/usuarios
✗ /api/usuario

3. Estructura Consistente

{
  "data": { /* contenido principal */ },
  "meta": { /* metadata */ },
  "links": { /* enlaces de navegación */ },
  "included": { /* recursos relacionados */ }
}

4. Códigos de Estado Apropiados

200 OK          → Éxito general
201 Created     → Recurso creado
204 No Content  → Éxito sin contenido
400 Bad Request → Petición inválida
401 Unauthorized → No autenticado
403 Forbidden   → No autorizado
404 Not Found   → Recurso no encontrado
422 Unprocessable Entity → Error de validación
500 Internal Server Error → Error del servidor

5. Filtrado y Paginación

# Filtros
GET /api/productos?categoria=electronica&precio_min=100

# Paginación
GET /api/productos?page=2&per_page=20

# Ordenamiento
GET /api/productos?sort=precio&order=desc

6. HATEOAS (Hypermedia as the Engine of Application State)

{
  "id": 123,
  "nombre": "Juan Pérez",
  "links": {
    "self": "/api/usuarios/123",
    "posts": "/api/usuarios/123/posts",
    "profile": "/api/usuarios/123/profile"
  }
}

Herramientas para APIs REST

Desarrollo

  • Postman: Testing de APIs
  • Insomnia: Cliente REST
  • Swagger/OpenAPI: Documentación
  • JSONPlaceholder: API de prueba

Testing

  • Newman: Postman en CLI
  • REST Assured: Testing en Java
  • SuperTest: Testing en Node.js
  • Pytest: Testing en Python

Documentación

  • Swagger UI: Interfaz interactiva
  • Redoc: Documentación estática
  • API Blueprint: Markdown para APIs
  • Postman Docs: Documentación automática

Relacionado

Términos Relacionados