Definición
Los códigos de estado 2xx de Éxito indican que la solicitud HTTP del cliente fue recibida, comprendida y aceptada exitosamente por el servidor. Estos códigos confirman que la operación se completó como se esperaba.
Los códigos de estado 2xx más comunes son:
- 200 OK - La solicitud tuvo éxito, la respuesta contiene los datos solicitados
- 201 Created - Nuevo recurso creado exitosamente
- 202 Accepted - Solicitud aceptada para procesamiento (operaciones asíncronas)
- 204 No Content - La solicitud tuvo éxito pero no hay contenido que devolver (ej. operaciones DELETE)
- 206 Partial Content - El servidor está devolviendo solo parte del recurso (solicitudes de rango)
Los códigos 2xx están definidos en el RFC 7231 y son fundamentales para el diseño de APIs RESTful, indicando operaciones CRUD exitosas.
Ejemplo
200 OK - GET Exitoso:
GET /api/users/123 HTTP/1.1
Host: api.example.com
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 142
{
"id": 123,
"name": "Alice Smith",
"email": "[email protected]",
"role": "developer"
}
201 Created - POST Exitoso:
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"name": "Bob Johnson",
"email": "[email protected]"
}
HTTP/1.1 201 Created
Location: /api/users/124
Content-Type: application/json
Content-Length: 168
{
"id": 124,
"name": "Bob Johnson",
"email": "[email protected]",
"createdAt": "2026-01-09T10:30:00Z"
}
204 No Content - DELETE Exitoso:
DELETE /api/users/123 HTTP/1.1
Host: api.example.com
Authorization: Bearer YOUR_TOKEN
HTTP/1.1 204 No Content
Date: Thu, 09 Jan 2026 10:30:00 GMT
202 Accepted - Procesamiento Asíncrono:
POST /api/reports/generate HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"reportType": "sales",
"dateRange": "2025-12-01/2025-12-31"
}
HTTP/1.1 202 Accepted
Location: /api/reports/status/abc-123
Content-Type: application/json
{
"status": "processing",
"statusUrl": "/api/reports/status/abc-123",
"estimatedCompletion": "2026-01-09T10:35:00Z"
}
Ejemplo de Código
JavaScript (Fetch API):
// Manejar 200 OK
const getUser = async (userId) => {
const response = await fetch(`https://api.example.com/users/${userId}`, {
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
}
});
if (response.status === 200) {
return await response.json();
}
throw new Error(`Estado inesperado: ${response.status}`);
};
// Manejar 201 Created
const createUser = async (userData) => {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
},
body: JSON.stringify(userData)
});
if (response.status === 201) {
const location = response.headers.get('Location');
console.log('Recurso creado en:', location);
return await response.json();
}
throw new Error(`Fallo al crear: ${response.status}`);
};
// Manejar 204 No Content
const deleteUser = async (userId) => {
const response = await fetch(`https://api.example.com/users/${userId}`, {
method: 'DELETE',
headers: {
'Authorization': 'Bearer YOUR_TOKEN'
}
});
if (response.status === 204) {
console.log('Usuario eliminado exitosamente');
return; // Sin contenido que parsear
}
throw new Error(`Fallo al eliminar: ${response.status}`);
};
// Manejar 202 Accepted (operaciones asíncronas)
const generateReport = async (reportData) => {
const response = await fetch('https://api.example.com/reports/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
},
body: JSON.stringify(reportData)
});
if (response.status === 202) {
const data = await response.json();
console.log('Generación de reporte iniciada:', data.statusUrl);
// Consultar URL de estado hasta completar
return await pollStatus(data.statusUrl);
}
throw new Error(`Fallo al iniciar reporte: ${response.status}`);
};
const pollStatus = async (statusUrl) => {
const maxAttempts = 60;
const delay = 2000; // 2 segundos
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(statusUrl, {
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
});
const data = await response.json();
if (data.status === 'completed') {
return data.result;
} else if (data.status === 'failed') {
throw new Error('La generación del reporte falló');
}
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Timeout en la generación del reporte');
};
Python (librería requests):
import requests
import time
# Manejar 200 OK
def get_user(user_id):
response = requests.get(
f'https://api.example.com/users/{user_id}',
headers={
'Accept': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
}
)
if response.status_code == 200:
return response.json()
raise Exception(f'Estado inesperado: {response.status_code}')
# Manejar 201 Created
def create_user(user_data):
response = requests.post(
'https://api.example.com/users',
json=user_data,
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
if response.status_code == 201:
location = response.headers.get('Location')
print(f'Recurso creado en: {location}')
return response.json()
raise Exception(f'Fallo al crear: {response.status_code}')
# Manejar 204 No Content
def delete_user(user_id):
response = requests.delete(
f'https://api.example.com/users/{user_id}',
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
if response.status_code == 204:
print('Usuario eliminado exitosamente')
return # Sin contenido que parsear
raise Exception(f'Fallo al eliminar: {response.status_code}')
# Manejar 202 Accepted (operaciones asíncronas)
def generate_report(report_data):
response = requests.post(
'https://api.example.com/reports/generate',
json=report_data,
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
if response.status_code == 202:
data = response.json()
print(f"Generación de reporte iniciada: {data['statusUrl']}")
# Consultar URL de estado hasta completar
return poll_status(data['statusUrl'])
raise Exception(f'Fallo al iniciar reporte: {response.status_code}')
def poll_status(status_url):
max_attempts = 60
delay = 2 # 2 segundos
for i in range(max_attempts):
response = requests.get(
status_url,
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
data = response.json()
if data['status'] == 'completed':
return data['result']
elif data['status'] == 'failed':
raise Exception('La generación del reporte falló')
time.sleep(delay)
raise Exception('Timeout en la generación del reporte')
Diagrama
graph TB
subgraph "Códigos 2xx de Éxito"
S200[200 OK
Éxito estándar]
S201[201 Created
Recurso creado]
S202[202 Accepted
Procesamiento asíncrono]
S204[204 No Content
Éxito, sin cuerpo]
S206[206 Partial Content
Solicitud de rango]
end
subgraph "Casos de Uso"
UC1[Solicitud GET]
UC2[POST crear]
UC3[Trabajo asíncrono]
UC4[Solicitud DELETE]
UC5[Streaming de video]
end
UC1 --> S200
UC2 --> S201
UC3 --> S202
UC4 --> S204
UC5 --> S206
S200 --> BODY1[Respuesta incluye cuerpo]
S201 --> BODY2[Respuesta incluye cuerpo
+ encabezado Location]
S202 --> BODY3[Respuesta incluye URL de estado]
S204 --> NOBODY[Sin cuerpo de respuesta]
S206 --> PARTIAL[Cuerpo de respuesta parcial
+ encabezado Content-Range]
Analogía
Piensa en los códigos de estado 2xx como diferentes tipos de confirmaciones de éxito:
- 200 OK → “Aquí está lo que pediste” (cajero te entrega tu cambio)
- 201 Created → “¡Creado! Aquí está tu recibo” (obtienes un nuevo número de cuenta)
- 202 Accepted → “Estamos trabajando en ello, vuelve más tarde” (pedido en preparación)
- 204 No Content → “¡Listo! Nada más que decir” (suscripción cancelada, no se necesita recibo)
Buenas Prácticas
- Usar el Código 2xx Correcto - No usar 200 para todo; usar 201 para creación, 204 para eliminación
- Incluir Encabezado Location - Siempre agregar encabezado
Locationcon 201 Created - Devolver Recurso Creado - Incluir el nuevo recurso en el cuerpo de respuesta 201
- Usar 202 para Asíncrono - Operaciones de larga duración deben devolver 202 con URL de estado
- Sin Cuerpo para 204 - Nunca incluir un cuerpo de respuesta con 204 No Content
- Estructura 200 Consistente - Usar el mismo formato de respuesta en todos los endpoints
- Incluir Metadatos - Agregar timestamps, versiones o ETags en respuestas exitosas
Errores Comunes
- 200 para Todo - Usar 200 OK para creaciones/eliminaciones en lugar de 201/204
- 201 sin Location - No incluir encabezado
Locational crear recursos - 204 con Cuerpo - Incluir cuerpo de respuesta con 204 No Content (viola la especificación)
- 202 Síncrono - Usar 202 para operaciones que se completan inmediatamente
- Sin URL de Estado - Devolver 202 sin proporcionar forma de verificar el estado
- Formato Inconsistente - Cambiar estructura de respuesta entre endpoints similares
- Sin Timestamps - No incluir
createdAtoupdatedAten las respuestas