Saber leer un curl pegado acelera el trabajo con APIs

Un comando curl copiado de la documentación o de las herramientas de desarrollo del navegador suele tener este aspecto:

curl -X POST 'https://api.example.com/v1/items?limit=10' \
  -H 'Authorization: Bearer TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Alice","tags":["a","b"]}'

Es sencillo una vez que se sabe leer, pero hay combinaciones de opciones que cambian el comportamiento, y desconocerlas lleva al clásico «el mismo comando no funciona aquí».

Tabla de opciones

OpciónSignificado
-X, --requestMétodo HTTP (GET / POST / PUT / DELETE)
-H, --headerAñade una cabecera; se puede repetir
-d, --dataEnvía un cuerpo. Implica POST
--data-rawIgual que -d, pero no trata la @ inicial como nombre de archivo
-F, --formEnvía como multipart/form-data (subida de archivos)
-u, --userAutenticación básica (usuario:contraseña)
-L, --locationSigue las redirecciones (3xx)
-o, --outputGuarda la respuesta en un archivo
-O, --remote-nameGuarda con el nombre que indica la URL
-s, --silentOculta el indicador de progreso
-S, --show-errorCon -s, muestra igualmente los errores
-i, --includeIncluye las cabeceras de respuesta en la salida
-I, --headEnvía HEAD y muestra solo las cabeceras
-v, --verboseMuestra todo el intercambio, cabeceras incluidas
-k, --insecureNo verifica el certificado del servidor
--compressedSolicita una transferencia comprimida
-b, --cookieEnvía cookies
-c, --cookie-jarGuarda en un archivo las cookies recibidas
-w, --write-outImprime datos como %{http_code} al terminar

-X POST suele sobrar

Añadir -d ya convierte la petición en POST. Estas dos son idénticas:

curl -X POST https://api.example.com/items -d '{"a":1}'
curl https://api.example.com/items -d '{"a":1}'

El problema es el caso contrario. -X GET junto con -d produce un GET con cuerpo, algo que proxies y servidores pueden ignorar o rechazar: una causa clásica de «funciona en local y falla en producción».

Repetir -d une los valores con &. Útil para formularios, fatal para JSON:

# No es lo que quiere: envía {"a":1}&{"b":2}
curl -d '{"a":1}' -d '{"b":2}' https://api.example.com/items

Una @ inicial en -d lee un archivo

Cuando el valor pasado a -d empieza por @, curl lee ese archivo y envía su contenido:

curl -d @payload.json https://api.example.com/items   # envía el contenido del archivo

Práctico, hasta que pasa un nombre de usuario tal cual:

# Intención: enviar la cadena "@alice"
# Realidad: curl busca el archivo ./alice y falla si no existe
curl -d '@alice' https://api.example.com/items

Para enviar un valor que contenga @ literalmente, use --data-raw, que no le da ningún significado especial.

El Content-Type no pasa a JSON por sí solo

Con -d, curl envía Content-Type: application/x-www-form-urlencoded salvo que indique otra cosa. Si manda JSON sin la cabecera, el servidor no podrá analizarlo:

curl -H 'Content-Type: application/json' \
     -d '{"name":"Alice"}' https://api.example.com/items

Desde curl 7.82 existe --json, que establece a la vez Content-Type: application/json y Accept: application/json. En entornos antiguos no está disponible, así que escriba la cabecera explícitamente en los comandos que vaya a compartir.

Las comillas causan más fallos que ninguna otra cosa

EstiloComportamiento
'...' (simples)Pasa $ y " sin tocarlos. Úselas para JSON
"..." (dobles)La shell expande $variables

El JSON contiene comillas dobles, así que las exteriores deben ser simples:

# Correcto
curl -d '{"name":"Alice"}' https://api.example.com/items

# La shell elimina las comillas interiores y el cuerpo se rompe
curl -d "{"name":"Alice"}" https://api.example.com/items

Cuando necesite un token desde una variable de entorno, combine ambas deliberadamente:

curl -H "Authorization: Bearer $TOKEN" \
     -d '{"name":"Alice"}' https://api.example.com/items

El símbolo del sistema de Windows no interpreta las comillas simples, y en PowerShell curl puede ser un alias de Invoke-WebRequest. Llame a curl.exe explícitamente o ejecute el comando en WSL o Git Bash.

Entrecomille las URL que contengan &

Si pega una URL con varios parámetros sin comillas, la shell interpreta & como «ejecutar en segundo plano» y trunca el comando:

# Roto: solo se envía limit=10
curl https://api.example.com/items?limit=10&offset=20

# Correcto
curl 'https://api.example.com/items?limit=10&offset=20'

Los valores con espacios o caracteres no ASCII necesitan codificación porcentual. Puede comprobarla con el codificador/decodificador de URL, o dejar que curl construya la cadena de consulta con -G y --data-urlencode:

curl -G https://api.example.com/search --data-urlencode 'q=hola mundo'

Dos opciones ante las que conviene dudar

-k / --insecure desactiva la verificación del certificado. Tiene sentido al probar un certificado autofirmado en local, pero el incidente clásico es añadirla para silenciar un error y dejarla en un comando compartido o en producción. Los problemas de certificado se arreglan en el certificado.

-L / --location sigue las redirecciones. Es cómodo, pero el tratamiento del método y del cuerpo en un POST redirigido puede cambiar; fíjelo con --post301, --post302 o --post303 cuando importe.

Convertir el comando en código

Una vez leído el comando, transcribir cabeceras y cuerpos a mano es propenso a errores. Péguelo en el conversor de cURL y obtendrá código de petición para JavaScript, Python, Go y otros lenguajes, con el entrecomillado y la separación de cabeceras ya resueltos.

Para formatear o validar el JSON que envía, use el formateador JSON; para inspeccionar una cadena de consulta, parámetros de URL a JSON. Todo se ejecuta en su navegador, así que un comando con un token de autenticación nunca se transmite.

Resumen

  • -d ya implica POST; -X GET con -d produce un incómodo GET con cuerpo
  • Un valor de -d que empieza por @ lee un archivo: use --data-raw para enviarlo como texto
  • -d por sí solo significa codificación de formulario. Para JSON, ponga la cabecera o use --json (curl 7.82+)
  • Comillas simples alrededor del JSON; dobles solo donde necesite expandir variables
  • Entrecomille las URL con &; construya consultas codificadas con -G --data-urlencode
  • -k no sirve para silenciar errores, y -L puede cambiar el comportamiento de un POST

Preguntas frecuentes

¿Hace falta escribir -X POST?

Normalmente no: añadir -d o -F convierte la petición en POST automáticamente. Escribirlo documenta la intención, lo cual tiene valor en un comando compartido. Lo que conviene evitar es -X GET junto con -d, que produce un GET con cuerpo y algunos servidores y proxies lo ignoran o lo rechazan.

¿Qué diferencia hay entre -d y --data-raw?

Solo el tratamiento de la @ inicial. Con -d, un valor que empieza por @ se toma como nombre de archivo y se envía su contenido; --data-raw envía la cadena tal cual. Use --data-raw para datos que contengan @ de forma legítima, como una dirección de correo.

He enviado JSON pero el servidor no lo interpreta

Con -d, el Content-Type por defecto es application/x-www-form-urlencoded, así que necesita -H 'Content-Type: application/json'. Desde curl 7.82, --json establece la cabecera por usted.

El comando no funciona en Windows

El símbolo del sistema no interpreta las comillas simples y PowerShell puede tener curl como alias de Invoke-WebRequest. Llame a curl.exe explícitamente o ejecute el comando desde una shell que maneje comillas simples, como WSL o Git Bash.

¿Es seguro pegar un comando que contiene un token?

El conversor de cURL funciona íntegramente en su navegador y nada de lo que pega se transmite. Eso sí, el código convertido sigue conteniendo el token, así que muévalo a una variable de entorno antes de subir el código.