Toda app que has usado son dos computadoras pasándose notas. HTTP es el formato de la nota — y es tan simple que puedes leerlo en crudo. Esta página: el modelo de petición/respuesta, lo que los códigos de estado realmente te dicen (401 vs 403, resuelto para siempre), REST sin la teología, y la verdad sobre el error de CORS.
🎙️ Publicado y grabado:
Todo HTTP es un intercambio: el cliente envía una petición (una nota estructurada), el servidor devuelve una respuesta (otra nota), y entonces — esta es la parte que la gente no pilla — el servidor olvida que exististe. HTTP es stateless. Toda "experiencia de sesión iniciada" que has vivido se construye re-mostrando un carné (una cookie o token) en cada nota.
## la petición — literalmente así de legible:
GET /users/42 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbG...
## la respuesta:
HTTP/1.1 200 OK
Content-Type: application/json
{"id": 42, "name": "Ada"}
Una URL es una dirección con cuatro partes funcionales: el protocolo, el edificio (host), la habitación (path) y las notas adhesivas en la puerta (query parameters). Aprende a leerlas y la documentación de APIs deja de dar miedo.
https://api.example.com/users/42/orders?status=paid&limit=10
└─┬──┘ └──────┬──────┘└──────┬──────┘ └────────┬─────────┘
scheme host path query params
(cómo) (qué servidor) (qué cosa) (opciones: clave=valor, separadas con &)
?api_key=sk_live_... es una clave que ya deberías considerar filtrada. Los secretos viajan en headers (sección 07), que no se registran por defecto.
El método le dice al servidor qué tipo de nota es. Cinco cubren todo: GET lee, POST crea, PUT reemplaza, PATCH edita una parte, DELETE borra. El concepto que vale la pena entender: idempotencia — ¿puedo enviar esto dos veces sin problema?
GET /users/42 # leer — nunca cambia nada
POST /users # crear uno nuevo ⚠ dos veces = dos usuarios
PUT /users/42 # reemplazar entero — dos veces = mismo resultado
PATCH /users/42 # cambiar algunos campos
DELETE /users/42 # borrar — dos veces = sigue borrado
Idempotency-Key, para que una petición reintentada cree un cobro, no dos. Cuando la red se corta a mitad de un POST, "¿se procesó o no?" es la razón entera de que exista esta palabra.
El primer dígito es toda la historia: 2xx funcionó, 3xx se movió, 4xx la regaste tú, 5xx la regaron ellos. Esa sola frase clasifica todo error de API que verás en "arregla mi petición" vs "espera / repórtalo". Y la pareja eterna de confusión, resuelta:
200 OK # aquí tienes
201 Created # creado (respuesta a un POST exitoso)
301 Moved # nueva dirección, ve allí
400 Bad Request # tu nota está malformada (JSON malo, campo faltante)
401 Unauthorized # ¿QUIÉN ERES? — sin credenciales o inválidas
403 Forbidden # Sé quién eres. No. — login válido, sin permisos
404 Not Found # no existe nada en esta ruta
429 Too Many Requests # más lento (rate limit — espera y reintenta)
500 Internal Error # el servidor crasheó. no es tu culpa
503 Unavailable # servidor sobrecargado/caído. tampoco es tu culpa
Los headers son metadatos en el sobre — qué formato, qué idioma, quién pregunta, qué credenciales. El body es la carta dentro — para APIs, casi siempre JSON. Vas a configurar dos headers constantemente y leer un tercero:
Content-Type: application/json # "el body que ENVÍO es JSON"
Authorization: Bearer <token> # "aquí va mi carné"
Accept: application/json # "por favor RESPONDE en JSON"
# el body (POST /users):
{ "name": "Ada", "country": "UK" }
400 Bad Request o un misterioso null en todo — porque olvidaste Content-Type: application/json, y el servidor interpretó tu JSON como un envío de formulario. El body estaba bien. La etiqueta del sobre estaba mal. Este solo header explica una década de preguntas en Stack Overflow.
curl envía peticiones HTTP desde la línea de comandos. Es cómo pruebas una API sin tu app de por medio — la mejor jugada de debugging: si curl funciona y tu código no, el bug está en tu código; si curl también falla, es la API. Divide y vencerás.
# leer
curl https://api.example.com/users/42
# crear (-X método, -H header, -d body)
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"name": "Ada"}'
# ver el CÓDIGO DE ESTADO y headers también (la vista de debugging)
curl -i https://api.example.com/users/42
Dos patrones cubren la mayoría de APIs. Un API key es una contraseña de larga duración para un programa. Un bearer token suele ser de corta vida, se obtiene al iniciar sesión, y se presenta como Authorization: Bearer … — "bearer" literalmente significa quien cargue esto, es esto. Lo cual es el modelo de seguridad y la advertencia de seguridad en una sola palabra.
# ambos viajan en el header Authorization:
Authorization: Bearer eyJhbGciOi... # token (a menudo un JWT)
x-api-key: sk_live_4242... # algunas APIs usan un header custom
# las claves viven en variables de entorno, nunca en el código:
curl -H "Authorization: Bearer $API_TOKEN" ...
REST es una convención de nombres, no una tecnología: las URLs nombran cosas (sustantivos), los métodos dicen qué hacer con ellas (verbos). Eso es el 90%. Una API es "RESTful" cuando puedes adivinar el siguiente endpoint sin leer la documentación — la predictibilidad es todo el punto.
# sustantivos en la URL, verbos en el método:
GET /articles # listar artículos
POST /articles # crear uno
GET /articles/7 # leer uno
PATCH /articles/7 # editarlo
DELETE /articles/7 # eliminarlo
GET /articles/7/comments # anidado: sus comentarios
✗ POST /getArticleById ✗ GET /deleteUser?id=7 # verbos en URLs = mal olor
Un día tu frontend llama a una API y la consola explota. El giro que todos se pierden: este error no es el servidor rechazándote — es tu propio navegador, aplicando una regla de seguridad: JavaScript del sitio A no puede leer respuestas del sitio B a menos que B lo permita explícitamente (mediante un header Access-Control-Allow-Origin). La prueba: la misma petición funciona perfecto en curl.
Access to fetch at 'https://api.other.com/data' from origin
'http://localhost:3000' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present...
# decodificando: api.other.com no dijo que localhost:3000 puede leerlo.
# el navegador obtuvo los datos — y luego se los ocultó a tu JS.
Las tablas mentales que responden el 90% de preguntas sobre APIs.
# métodos
GET leer · POST crear (⚠ no seguro de reintentar) · PUT reemplazar
PATCH editar · DELETE eliminar
# estado: primer dígito = quién la regó
2xx ✓ · 3xx se movió · 4xx tú · 5xx ellos
401 ¿quién eres? → arregla el token
403 ¿tú específicamente? no. → arregla los permisos
429 más lento → espera y reintenta
# el POST que "misteriosamente" falla
→ ¿enviaste Content-Type: application/json ?
# orden de debugging
curl -i primero. código después.
curl funciona + código falla → tu bug
curl también falla → su bug (o tu token)
# error de CORS en la consola
→ regla del navegador, el servidor debe permitirlo. curl prueba que la API funciona.
# secretos
headers ✓ · env vars ✓ · URLs ✗ · git ✗ · frontend ✗
Ese es el núcleo funcional. Todo lo más avanzado — webhooks, GraphQL, gRPC — es una variación de las mismas dos notas. Cuando quieras llamar APIs desde código, Python más esta página es un toolkit completo.