Enviar peticiones con curl y Postman
Las dos herramientas que usarás cada día, y cuándo elegir cada una.
Hasta ahora has enviado peticiones desde un navegador y desde los botones Enviar de estas páginas. Eso sirve para peticiones GET sencillas y para nada más. Para elegir el método, fijar cabeceras o enviar un cuerpo necesitas un cliente de verdad. Casi todo el que prueba APIs acaba usando dos: curl en la línea de comandos y un cliente gráfico como Postman. Esta lección cubre lo suficiente de cada uno para seguir el resto del tutorial.
curl
curl es un programa de línea de comandos que envía una petición e imprime la respuesta. Viene instalado por defecto en macOS, en la mayoría de los sistemas Linux y en Windows 10 y 11. Compruébalo con curl --version. También es el formato que usan los desarrolladores para compartir peticiones: la documentación de las APIs, las herramientas de desarrollo del navegador y Postman pueden mostrar o exportar una petición como un comando curl, así que necesitarás leerlos aunque prefieras otra herramienta.
Sin opciones, curl imprime solo el cuerpo. Añade -i para incluir la línea de estado y las cabeceras de respuesta, que casi siempre querrás ver al probar:
curl -i https://api.testingapis.com/api/healthHTTP/1.1 200 OK
content-type: application/json; charset=utf-8
date: Sun, 11 Oct 2026 11:47:45 GMT
server: Kestrel
x-powered-by: TestingAPIs
transfer-encoding: chunked
{"status":"healthy","uptimeSeconds":76890,"timestamp":"2026-10-11T11:47:46Z"}Para más detalle, -v (detallado) también imprime la petición que envió curl, marcada con >, y las cabeceras de respuesta, marcadas con <. Las líneas que empiezan por * describen la conexión. Úsalo cuando una petición no se comporte como esperas y quieras ver exactamente qué pasó por el cable.
curl -v https://api.testingapis.com/api/health* Host api.testingapis.com:443 was resolved.
* IPv4: 135.13.233.203
* Established connection to api.testingapis.com (135.13.233.203 port 443)
* using HTTP/1.x
> GET /api/health HTTP/1.1
> Host: api.testingapis.com
> User-Agent: curl/8.18.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< content-type: application/json; charset=utf-8
< date: Sun, 11 Oct 2026 11:49:47 GMT
< transfer-encoding: chunked
...curl añadió tres cabeceras que no pediste: Host, User-Agent y Accept. Todos los clientes añaden algunas por defecto, y cada cliente añade unas distintas. Cuando la misma petición funciona en Postman y falla en curl, una cabecera por defecto suele ser la causa.
Método, cabeceras y cuerpo
Tres opciones cubren la mayoría de las peticiones. -X fija el método. -H añade una cabecera y se puede repetir. -d envía un cuerpo. Esto envía un POST con un cuerpo JSON a un endpoint que devuelve lo que recibió:
curl -X POST https://api.testingapis.com/api/methods/post \
-H "Content-Type: application/json" \
-d '{"name":"Asha","role":"tester"}'{"method":"POST","message":"POST request received","path":"/api/methods/post","query":{},"contentType":"application/json","bodyLength":31,"bodyTruncated":false,"body":"{\"name\":\"Asha\",\"role\":\"tester\"}","timestamp":"2026-09-30T18:31:16Z"}La barra invertida al final de cada línea permite que el comando continúe en la línea siguiente en bash y zsh. El cuerpo va entre comillas simples para que el shell no toque las comillas dobles de dentro. Si olvidas la cabecera Content-Type, curl envía application/x-www-form-urlencoded, porque -d se diseñó para formularios HTML, y muchas APIs rechazarán el cuerpo.
curl 7.82 y posteriores tienen un atajo, --json, que envía el cuerpo, fija Content-Type: application/json y Accept: application/json, y cambia el método a POST. Este crea una tarea de verdad:
curl --json '{"title":"Learn curl","completed":false,"userId":1}' \
https://api.testingapis.com/api/Todos{"message":"Todo created successfully","data":{"id":31,"userId":1,"title":"Learn curl","completed":false,"priority":"medium","dueDate":""}}El ID que recibas será distinto, porque otras personas también crean tareas. Para PUT o PATCH, añade -X PUT o -X PATCH junto a --json.
Tiempos y scripts
-w imprime valores que midió curl, después de la respuesta. Combinado con -s (silencioso, sin barra de progreso) y -o /dev/null (descartar el cuerpo), te da un resumen en una línea:
curl -s -o /dev/null \
-w "status %{http_code} total %{time_total}s size %{size_download} bytes\n" \
https://api.testingapis.com/api/Productsstatus 200 total 0.382512s size 5846 bytesEn Windows, usa -o NUL en lugar de -o /dev/null. time_total incluye la consulta DNS, la conexión y TLS, así que la primera petición suele ser más lenta que las siguientes. La lección de rendimiento desglosa más este número.
curl en Windows
Windows necesita su propia sección, porque el mismo comando puede comportarse de tres maneras según el shell.
En Windows PowerShell 5.1 (la versión que viene con Windows), curl no es curl. Es un alias de Invoke-WebRequest, un comando de PowerShell con otras opciones, así que curl -i falla con un error confuso. Escribe curl.exe para ejecutar el programa real. PowerShell 7 eliminó el alias, pero escribir curl.exe funciona en los dos, así que es una buena costumbre.
Las comillas son el segundo problema. Windows PowerShell 5.1 quita las comillas dobles de dentro de los argumentos cuando se los pasa a programas como curl.exe. El comando de abajo parece correcto, y el servidor recibe JSON roto:
PS> curl.exe -s -X POST https://api.testingapis.com/api/methods/post -H "Content-Type: application/json" -d '{"name":"Asha"}'
{"method":"POST", ... "bodyLength":11, ... "body":"{name:Asha}", ...}El cuerpo llegó como {name:Asha}, que no es JSON. PowerShell 7.3 y posteriores pasan las comillas correctamente. En versiones anteriores, el arreglo menos doloroso es poner el cuerpo en un archivo y apuntar curl a él con @. Las comillas alrededor de "@body.json" evitan que PowerShell trate la @ como sintaxis propia.
# body.json contains {"name":"Asha","role":"tester"}
curl.exe -s --json "@body.json" https://api.testingapis.com/api/methods/postEn el antiguo Símbolo del sistema (cmd.exe), las comillas simples no significan nada, así que envuelve el cuerpo en comillas dobles y escapa las de dentro con una barra invertida. El carácter de continuación de línea es ^ en lugar de la barra invertida:
curl -X POST https://api.testingapis.com/api/methods/post ^
-H "Content-Type: application/json" ^
-d "{\"name\":\"Asha\",\"role\":\"tester\"}"Postman y otros clientes gráficos
Un cliente gráfico hace el mismo trabajo que curl con un formulario en lugar de un comando: eliges el método en un desplegable, escribes la URL, rellenas cabeceras y cuerpo en pestañas y haces clic en Send. La respuesta aparece debajo, formateada, con el estado, el tiempo y el tamaño. Postman es el más usado. Insomnia y Bruno funcionan igual, y Bruno guarda todo como archivos de texto, algo que algunos equipos prefieren porque las peticiones pueden vivir en el mismo repositorio Git que el código. Las ideas de abajo valen para todos, con los nombres de Postman.
Colecciones
Una colección es un grupo guardado de peticiones, normalmente una por API, con carpetas dentro. Es la razón para elegir un cliente gráfico en lugar de curl en un proyecto en el que trabajas durante meses. Construyes las peticiones una vez y compartes la colección con el equipo.
No tienes que construirla a mano. Esta API publica un documento OpenAPI, una descripción legible por máquinas de cada endpoint, en https://api.testingapis.com/openapi/v1.jsoninicia sesión para verlo. En Postman, elige Import, pega esa URL y crea una colección con una petición por endpoint. La mayoría de las APIs que pruebes en el trabajo tendrán un archivo parecido, y es la forma más rápida de empezar con una que no conoces.
Entornos y variables
Los proyectos reales ejecutan la misma API en varios sitios: el portátil de un desarrollador, un servidor de pruebas, staging, producción. Las peticiones son las mismas salvo la URL base y las credenciales. Postman lo resuelve con entornos. Crea uno llamado "testingapis" con una variable baseUrl con el valor https://api.testingapis.com, y escribe las URLs de tus peticiones como {{baseUrl}}/api/Products/1. Cambiar de entorno cambia todas las peticiones a la vez. Pon también los tokens en variables, para no copiarlos en docenas de peticiones.
Tests en Postman
Cada petición tiene una pestaña Tests (en versiones nuevas se llama Scripts, con una sección post-response) donde puedes escribir JavaScript que se ejecuta cuando llega la respuesta. Para GET {{baseUrl}}/api/Products/1:
pm.test("status is 200", function () {
pm.response.to.have.status(200);
});
pm.test("product 1 has a price", function () {
const product = pm.response.json();
pm.expect(product.id).to.eql(1);
pm.expect(product.price).to.be.a("number");
});Los resultados aparecen en una pestaña Test Results junto a la respuesta. Después, el Collection Runner puede ejecutar todas las peticiones de una colección e informar de qué comprobaciones fallaron. Es un primer paso suave hacia la automatización. La lección de automatización trata de escribir tests como código normal, que escala mejor cuando tienes más de unas pocas docenas.
Cuál usar
Los dos, para trabajos distintos.
| Situación | Mejor opción |
|---|---|
| Comprobar una cosa rápido, o reproducir un informe de bug | curl |
| Compartir una petición exacta en un ticket o un chat | curl (cualquiera puede pegarla y ejecutarla) |
| Explorar una API que todavía no conoces | Cliente gráfico con la importación de OpenAPI |
| Cuerpos JSON largos que editas una y otra vez | Cliente gráfico |
| Cambiar entre servidores de pruebas y de staging | Entornos del cliente gráfico |
| Ejecutar dentro de un script o en un servidor de builds | curl, o tests escritos en código |
| Mirar cabeceras en bruto y detalles de la conexión | curl -v |
Una opción más, solo para esta API: cada página de endpoint de la referencia de la API tiene un formulario para enviar la petición y muestra un comando curl listo para copiar. A menudo es la forma más rápida de probar un endpoint antes de guardarlo en ningún sitio.
- Cuando un informe de bug incluya una petición, adjúntala como comando curl. El desarrollador puede ejecutarla sin importar nada, y no hay dudas sobre qué cabeceras se enviaron.
- Postman convierte en los dos sentidos. Pega un comando curl en el diálogo Import para obtener una petición, o usa el botón Code de una petición para obtener curl.
Ejercicio
Haz esto con curl y luego repítelo en un cliente gráfico.
- Envía
GET /api/echo/headersy compara las cabeceras que envía curl con las que envía tu cliente gráfico. ¿Qué cabeceras añadió cada herramienta por su cuenta? - Crea una tarea con
POST /api/Todosy luego recupérala conGET /api/Todos/seguido del ID de la respuesta. - Envía el mismo POST sin la cabecera
Content-Type. ¿Qué estado y qué cuerpo vuelven? - Usa
-wpara medir/api/Productsy/api/Products?delay=2. El parámetrodelayhace esperar al servidor, así que la segunda debería tardar unos dos segundos más.
En tu cliente gráfico, crea un entorno con una variable baseUrl y escribe un test que falle a propósito, para que sepas cómo es un fallo antes de fiarte de un aprobado.