cURLParse cURL Converter

cURL Best Practices: Writing HTTP Requests You Won't Have to Debug Twice

cURLParse — Convert cURL Commands to Python, Node.js, Go & Rust Guides · Updated 2026-10-01 · All guides

curl is the only HTTP client that ships with every server on earth. That also makes it the most copy-pasted and most mis-configured one. These are the practices that turn it from folklore into tooling.

Make failures loud

The default curl succeeds on a 500. curl https://api.example.com exiting 0 after receiving {"error":"db down"} has burned entire dashboards. The fix is a flag set, not a habit:

curl -sS --fail-with-body \
  --connect-timeout 5 --max-time 30 \
  -w '\n%{http_code}\n' \
  'https://api.example.com/health'
  • -sS: quiet progress bar, but real errors still print. (-s alone is how people lose DNS errors.)
  • --fail-with-body: non-zero exit on 4xx/5xx and the error body still prints. Prefer it over -f, which hides the body — the only interesting part.
  • --connect-timeout + --max-time: without both, a blackholed TCP handshake waits ~130s and your CI watchdog kills the wrong thing.

Quote like the shell is adversarial

Single quotes around every header and payload that contains no $variables. Double quotes only when you deliberately want interpolation — and never around JSON you didn't write, because $(...) inside double quotes is a command, not a string. The full taxonomy of how this breaks per shell is in quoting hell.

Be explicit about the body's identity

-d silently implies two things: the method becomes POST, and Content-Type becomes application/x-www-form-urlencoded. If you meant JSON, say so — -H 'Content-Type: application/json' — or your "JSON API call" is a form POST wearing a costume. This exact mismatch is the #1 reason converted code fails.

Read the response, not just the output

Add -i (or -D -) until the request is stable. Half of "it worked in curl" reports are people who never looked at the status line and saw a plausible-looking error body. -w '%{http_code}\n' is the assertion-friendly version for scripts.

Convert before you hand-write

When you move a working curl command into Python/Node/Go, don't rewrite from memory — convert it and read the diff. Our converter maps headers, body encoding, and auth explicitly so the diff shows real semantic choices (form vs JSON, session jar vs bare request) instead of library defaults you didn't choose. The five ways that diff usually saves you are enumerated in the debugging guide linked above.

Prefer honest method flags

Delete -X GET (a no-op that can defeat caching). Keep -X POST when the payload is -d — it's redundant to curl but load-bearing for the human reading the command. See the flags that matter for the fifteen options that carry the other 215.

Scripts: exit codes over string matching

code=$(curl -sS -o /tmp/resp.json -w '%{http_code}' --fail-with-body "$URL") || {
  cat /tmp/resp.json  # the error body explains everything
  exit 1
}

--fail-with-body gives you the exit code; -o + -w give you the code without contaminating stdout. This pattern retires every grep -q ok healthcheck you've ever seen.

FAQ

Is -k ever acceptable? In a lab against a self-signed cert, yes, with a comment. In CI or production, no — ship the CA bundle and use --cacert. -k doesn't skip a warning, it skips the security model.

Should I always add --compressed? For interactive use, fine. In scripts, only when the source command had it — the converter keeps it when it changes the response, and your timing measurements are meaningless if half your samples are compressed and half aren't.

What replaces -v for CI logs? --trace-ascii trace.log. Verbose mode interleaves body and headers and truncates; trace is complete and separable.

Developer Sponsor / Partner
Copied to clipboard!