Saltar al contenido principal

📬 Métodos HTTP

📖 Definición

Métodos HTTP representan la acción que un cliente quiere que el servidor realice. Cada método tiene un significado y propósito específico, siendo fundamental para el diseño de APIs RESTful.

🎯 Comprendiendo con analogías

Sistema de biblioteca

GET    = Buscar un libro (consulta)
├─ Preguntar al bibliotecario "¿Tienen este libro?"
├─ Solo recupera datos
└─ Sin cambiar el estado de la biblioteca

POST = Registrar un nuevo libro (creación)
├─ Añadir un libro nuevo a la biblioteca
├─ Cambia el estado de la biblioteca
└─ Crea un nuevo recurso

PUT = Actualizar toda la información del libro (actualización total)
├─ Reescribir toda la información del libro
└─ Reemplaza completamente

PATCH = Actualizar parte de la información del libro (actualización parcial)
├─ Modificar solo parte de la información (ej. disponibilidad)
└─ Cambiar solo una parte

DELETE = Dar de baja un libro (eliminación)
├─ Eliminar el libro de la biblioteca
└─ Eliminar un recurso

💡 Métodos HTTP principales

GET - Consultar datos

Propósito: Recuperar recursos del servidor

Características:
├─ Seguro (Safe): No modifica el estado del servidor
├─ Idempotente: Múltiples llamadas devuelven el mismo resultado
├─ Puede ser cacheado
└─ Permanece en el historial del navegador

Ejemplo de solicitud:
GET /api/users HTTP/1.1
Host: example.com
// API Fetch de JavaScript
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => console.log(data));

// jQuery
$.get('https://api.example.com/users', function(data) {
console.log(data);
});

// axios
axios.get('https://api.example.com/users')
.then(response => console.log(response.data));
# curl
curl https://api.example.com/users

# Consultar usuario específico
curl https://api.example.com/users/123

# Usar parámetros de consulta
curl "https://api.example.com/users?page=1&limit=10"

Ejemplo de respuesta:

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

{
"users": [
{ "id": 1, "name": "María González" },
{ "id": 2, "name": "Carlos Sánchez" }
]
}

POST - Crear datos

Propósito: Crear un nuevo recurso en el servidor

Características:
├─ No es seguro: Cambia el estado del servidor
├─ No es idempotente: Varias llamadas crean múltiples recursos
├─ No puede ser cacheado
└─ Incluye datos en el cuerpo de la solicitud

Ejemplo de solicitud:
POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json

{
"name": "María González",
"email": "maria@example.com"
}
// API Fetch
fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'María González',
email: 'maria@example.com'
})
})
.then(response => response.json())
.then(data => console.log(data));

// axios
axios.post('https://api.example.com/users', {
name: 'María González',
email: 'maria@example.com'
})
.then(response => console.log(response.data));
# curl
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name":"María González","email":"maria@example.com"}'

Ejemplo de respuesta:

HTTP/1.1 201 Created
Location: /api/users/123
Content-Type: application/json

{
"id": 123,
"name": "María González",
"email": "maria@example.com",
"createdAt": "2025-01-26T10:00:00Z"
}

PUT - Actualización total de datos

Propósito: Reemplazar completamente un recurso con nuevos datos

Características:
├─ No es seguro: Cambia el estado del servidor
├─ Idempotente: Múltiples llamadas producen el mismo resultado
├─ Reemplaza todo el recurso
└─ Puede crear el recurso si no existe

Ejemplo de solicitud:
PUT /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json

{
"name": "María González",
"email": "nuevo-email@example.com",
"phone": "666123456"
}
// API Fetch
fetch('https://api.example.com/users/123', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'María González',
email: 'nuevo-email@example.com',
phone: '666123456'
})
})
.then(response => response.json())
.then(data => console.log(data));

// axios
axios.put('https://api.example.com/users/123', {
name: 'María González',
email: 'nuevo-email@example.com',
phone: '666123456'
})
.then(response => console.log(response.data));
# curl
curl -X PUT https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"name":"María González","email":"nuevo-email@example.com","phone":"666123456"}'

PATCH - Actualización parcial de datos

Propósito: Modificar solo una parte del recurso

Características:
├─ No es seguro: Cambia el estado del servidor
├─ Puede ser o no idempotente
├─ Modifica solo algunos campos
└─ Más eficiente que PUT

Ejemplo de solicitud:
PATCH /api/users/123 HTTP/1.1
Host: example.com
Content-Type: application/json

{
"email": "nuevo-email@example.com"
}
// API Fetch
fetch('https://api.example.com/users/123', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: 'nuevo-email@example.com'
})
})
.then(response => response.json())
.then(data => console.log(data));

// axios
axios.patch('https://api.example.com/users/123', {
email: 'nuevo-email@example.com'
})
.then(response => console.log(response.data));
# curl
curl -X PATCH https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"email":"nuevo-email@example.com"}'

Comparación PUT vs PATCH:

Datos originales:
{
"id": 123,
"name": "María González",
"email": "antiguo@example.com",
"phone": "666111222"
}

Solicitud PUT (reemplaza completamente):
{
"name": "María González",
"email": "nuevo@example.com"
}
Resultado:
{
"id": 123,
"name": "María González",
"email": "nuevo@example.com"
// ¡Campo de teléfono desaparece!
}

Solicitud PATCH (modificación parcial):
{
"email": "nuevo@example.com"
}
Resultado:
{
"id": 123,
"name": "María González",
"email": "nuevo@example.com",
"phone": "666111222"
// ¡Campo de teléfono se mantiene!
}

DELETE - Eliminar datos

Propósito: Eliminar un recurso

Características:
├─ No es seguro: Cambia el estado del servidor
├─ Idempotente: Múltiples llamadas producen el mismo resultado
├─ El cuerpo de respuesta puede estar vacío
└─ Potencialmente irreversible

Ejemplo de solicitud:
DELETE /api/users/123 HTTP/1.1
Host: example.com
// API Fetch
fetch('https://api.example.com/users/123', {
method: 'DELETE'
})
.then(response => {
if (response.ok) {
console.log('Eliminación completada');
}
});

// axios
axios.delete('https://api.example.com/users/123')
.then(response => console.log('Eliminación completada'));
# curl
curl -X DELETE https://api.example.com/users/123

Ejemplo de respuesta:

HTTP/1.1 204 No Content

O

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

{
"message": "Usuario eliminado",
"deletedId": 123
}

🔍 Otros métodos HTTP

HEAD - Solo consultar encabezados

Propósito: Igual que GET, pero solo devuelve encabezados sin cuerpo

Casos de uso:
├─ Verificar existencia de recurso
├─ Comprobar tamaño de archivo
└─ Verificar tiempo de modificación

Ejemplo:
HEAD /api/users/123 HTTP/1.1
Host: example.com

Respuesta:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 256
Last-Modified: Sat, 26 Jan 2025 10:00:00 GMT
# curl
curl -I https://api.example.com/users/123

OPTIONS - Verificar métodos soportados

Propósito: Verificar métodos soportados por el servidor (usado en preflight de CORS)

Ejemplo:
OPTIONS /api/users HTTP/1.1
Host: example.com

Respuesta:
HTTP/1.1 200 OK
Allow: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Origin: *
# curl
curl -X OPTIONS https://api.example.com/users -i

📊 Comparación de atributos de métodos

┌─────────┬──────┬────────┬─────────┬────────────┐
│ Método │ Seguro│ Idempot│ Cacheable│ Cuerpo req│
├─────────┼──────┼────────┼─────────┼────────────┤
│ GET │ ✅ │ ✅ │ ✅ │ ❌ │
│ POST │ ❌ │ ❌ │ ❌ │ ✅ │
│ PUT │ ❌ │ ✅ │ ❌ │ ✅ │
│ PATCH │ ❌ │ △ │ ❌ │ ✅ │
│ DELETE │ ❌ │ ✅ │ ❌ │ △ │
│ HEAD │ ✅ │ ✅ │ ✅ │ ❌ │
│ OPTIONS │ ✅ │ ✅ │ ❌ │ ❌ │
└─────────┴──────┴────────┴─────────┴────────────┘

Explicación de términos:
- Seguro (Safe): No modifica estado del servidor
- Idempotente: Múltiples ejecuciones producen mismo resultado
- Cacheable: Respuesta puede ser cacheada

💡 Diseño de API RESTful

Mapeo CRUD con métodos HTTP

Create  → POST
Read → GET
Update → PUT / PATCH
Delete → DELETE

Ejemplo de API RESTful

Recurso: Usuarios (users)

GET /users - Listar usuarios
GET /users/123 - Consultar usuario
POST /users - Crear usuario
PUT /users/123 - Modificar usuario completamente
PATCH /users/123 - Modificar usuario parcialmente
DELETE /users/123 - Eliminar usuario

Recursos anidados:
GET /users/123/posts - Listar publicaciones de usuario
GET /users/123/posts/456 - Consultar publicación
POST /users/123/posts - Crear publicación
PUT /users/123/posts/456 - Modificar publicación
DELETE /users/123/posts/456 - Eliminar publicación

Ejemplo práctico: API de blog

// API de publicaciones de blog

// 1. Listar publicaciones (paginación, filtrado)
GET /api/posts?page=1&limit=10&category=tech

// 2. Consultar publicación específica
GET /api/posts/123

// 3. Crear publicación
POST /api/posts
{
"title": "Dominando métodos HTTP",
"content": "...",
"category": "tech"
}

// 4. Modificar publicación completamente
PUT /api/posts/123
{
"title": "Dominando métodos HTTP (actualizado)",
"content": "...",
"category": "tech"
}

// 5. Modificar parcialmente (incrementar visualizaciones)
PATCH /api/posts/123
{
"views": 101
}

// 6. Eliminar publicación
DELETE /api/posts/123

// 7. Relacionados con comentarios
GET /api/posts/123/comments - Listar comentarios
POST /api/posts/123/comments - Crear comentario
DELETE /api/posts/123/comments/456 - Eliminar comentario

🤔 Preguntas frecuentes

Q1. ¿Cuál es la diferencia entre POST y PUT?

R:

POST:
├─ Crear nuevo recurso
├─ Servidor decide URI del recurso
├─ No idempotente (varias llamadas crean varios recursos)
└─ Ejemplo: POST /users

PUT:
├─ Reemplazar recurso completamente
├─ Cliente especifica URI del recurso
├─ Idempotente (múltiples llamadas mismo resultado)
└─ Ejemplo: PUT /users/123

Analogía práctica:
POST = "Por favor, cree una nueva cuenta" (banco asigna número)
PUT = "Reemplace completamente la información de la cuenta 123"

Q2. ¿Puedo enviar un cuerpo en una solicitud GET?

R:

Técnicamente posible, pero:
├─ Permitido en especificación HTTP, no recomendado
├─ Muchos servidores/frameworks lo ignoran
├─ Problemas en caché y registro
└─ Se recomienda usar parámetros de consulta

❌ Ejemplo incorrecto:
GET /api/users
{
"filters": { "age": 25 }
}

✅ Ejemplo correcto:
GET /api/users?age=25

O para búsquedas complejas, usar POST:
POST /api/users/search
{
"filters": { "age": 25, "city": "Madrid" }
}

Q3. ¿Puedo enviar un cuerpo en una solicitud DELETE?

R:

Posible, pero con precaución:
├─ Permitido en especificación HTTP
├─ Algunos servidores/proxies pueden ignorarlo
├─ Normalmente ID de recurso en URI
└─ Cuerpo para información adicional

Ejemplos de uso:

✅ Método tradicional:
DELETE /api/users/123

✅ Eliminación por lotes:
DELETE /api/posts/bulk
{
"ids": [1, 2, 3, 4, 5]
}

✅ Enviar razón de eliminación:
DELETE /api/users/123
{
"reason": "Solicitud de usuario",
"confirm": true
}

Q4. ¿Por qué es importante la idempotencia?

R:

Importancia de la idempotencia:

1. Respuesta a fallos de red
├─ Posibilidad de reintentar solicitudes
├─ Sin preocupación por solicitudes duplicadas
└─ Reprocesamiento seguro

Ejemplos:
GET /users/123 → Seguro consultar varias veces
POST /users → ¡Varias llamadas crean múltiples usuarios!
PUT /users/123 → Múltiples llamadas mismo resultado
DELETE /users/123 → Múltiples eliminaciones mismo resultado

2. Lógica de reintento de cliente
├─ Reintentar de forma segura en caso de timeout
└─ Implementar mecanismos de reintento automático

3. Caché y optimización
├─ Solicitudes idempotentes pueden ser cacheadas
└─ Optimización de rendimiento

Q5. ¿Cuáles son los criterios para elegir método en la práctica?

R:

Guía de selección:

1. Solo consulta de datos
→ GET

2. Crear nuevo dato
→ POST

3. Reemplazar completamente datos
→ PUT
Ejemplo: Actualización completa de perfil

4. Modificar parte de los datos
→ PATCH
Ejemplo: Incrementar número de likes, cambiar estado

5. Eliminar datos
→ DELETE

6. Consulta/búsqueda compleja
→ POST /search
(Evitar límites de longitud de URL de GET)

Ejemplo práctico:

// ✅ Buen ejemplo
GET /api/products - Listar productos
GET /api/products/123 - Detalles de producto
POST /api/products - Registrar producto
PATCH /api/products/123/stock - Modificar solo stock
PUT /api/products/123 - Modificar información completa
DELETE /api/products/123 - Eliminar producto

// ❌ Mal ejemplo
GET /api/deleteProduct?id=123 - Eliminar con GET
POST /api/getProducts - Consultar con POST
POST /api/updateProduct - Modificar con POST

🎓 Prácticas

1. Práctica con API Fetch

// Solicitud GET
async function getUser(id) {
const response = await fetch(`https://api.example.com/users/${id}`);
const data = await response.json();
return data;
}

// Solicitud POST
async function createUser(userData) {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
return await response.json();
}

// Solicitud PUT
async function updateUser(id, userData) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(userData)
});
return await response.json();
}

// Solicitud PATCH
async function patchUser(id, partialData) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(partialData)
});
return await response.json();
}

// Solicitud DELETE
async function deleteUser(id) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'DELETE'
});
return response.ok;
}

2. Manejo de errores

async function apiRequest(url, options = {}) {
try {
const response = await fetch(url, options);

if (!response.ok) {
throw new Error(`Error HTTP! estado: ${response.status}`);
}

return await response.json();
} catch (error) {
console.error('Solicitud API fallida:', error);
throw error;
}
}

// Ejemplo de uso
try {
const user = await apiRequest('https://api.example.com/users/123');
console.log(user);
} catch (error) {
console.error('Consulta de usuario fallida');
}

🔗 Documentos relacionados

🎬 Conclusión

¡Los métodos HTTP son fundamentales para las API RESTful! Comprender las características de cada método te permitirá diseñar APIs intuitivas y fáciles de mantener.

Siguiente paso: Lee Códigos de estado HTTP para entender 200, 404, 500 y otros códigos.