Skip to main content
Back to BlogDeveloper Guides

How to Convert cURL to Code (the Regex Parser, the Four Vanishing Flags, and the Body That Guesses JSON)

Convert cURL commands to 14 languages — and learn why -k and --compressed silently disappear, why -F form data is parsed but never emitted, why the JSON-vs-string decision is a single character, and why the JS output isn't runnable as-is.

The Toolbox TeamAugust 14, 20267 min read

The cURL you copied from DevTools has more in it than the code shows

You right-click a network request in Chrome, "Copy as cURL", and paste it into the cURL to Code Converter. Out comes a JavaScript fetch call. It looks right. It runs. And four things in the original command — the -k that skipped a self-signed cert, the --compressed that set Accept-Encoding, the -F that uploaded a file, the absence of -L that stopped curl following a 302 — quietly stopped existing. The code does something different from what the cURL did. The converter is a regex parser, not a shell tokenizer, and it drops what its regexes don't catch.

Fourteen languages, not three

The FAQ says "JavaScript, Python, PHP." The actual count is 14, grouped in the picker by family:

  • JavaScript (4): fetch, axios, node-fetch, TypeScript fetch
  • Python (2): requests, httpx
  • PHP, Go, Ruby, Java, C#, Rust, Kotlin, Swift (one each)

Pick the one your codebase uses, not the default. The default is javascript-fetch, and it has a problem the others don't.

The parser is regex, not a shell tokenizer

cURL is a shell command with quoting rules. The converter doesn't run a shell — it runs regular expressions over the flattened string. Two consequences bite:

  1. Unquoted headers are silently dropped. The header regex is -H ['"]([^'"]+)['"] — it requires quotes. -H Content-Type:application/json (no quotes) matches nothing and vanishes. Chrome's "Copy as cURL" always quotes, so this only bites hand-typed commands — but it bites silently, no warning.

  2. A quote inside a value ends the value. [^'"]+ stops at the first quote of either kind. -H "X-Custom: it's a test" captures X-Custom: it and drops the rest. Use the other quote char or escape — the parser doesn't.

Line continuations (\ + newline) collapse to spaces, and all whitespace runs become a single space. Fine for flags, destructive for pretty-printed JSON — the indentation is gone before generation runs.

The four flags that silently disappear

Verified by reading every generator in the file:

  1. -k / --insecure is parsed but never emitted. result.insecure is set; no generator reads it. A cURL that skipped TLS verification converts to code that verifies TLS. If you hit a self-signed endpoint, the generated code throws where the cURL succeeded — and nothing in the output tells you why.

  2. --compressed is parsed but never emitted. Same shape: result.compressed is set, never used. cURL with --compressed sends Accept-Encoding: gzip and decodes the response. The generated code does neither. A response that was only legible because cURL decompressed it now comes back as raw bytes.

  3. -F / --form is parsed but never emitted. formData is collected — the UI even shows a "Form data" badge — but no generator builds a multipart body. A curl -F file=@photo.png converts as if it had no body at all. Silent data loss; the badge is the only trace.

  4. Redirect semantics flip. cURL without -L does not follow redirects. The generator emits redirect: 'manual' (fetch) / allow_redirects=False (requests) only when followRedirects === false — but with no -L, followRedirects is undefined, not false, so the clause is skipped. fetch defaults to following redirects; requests defaults to following. So "no -L" in cURL becomes "follow redirects" in the output — the opposite behavior, with no visible difference in the generated code.

The body that guesses JSON from one character

Every generator decides json= vs data= (or JSON.stringify vs a raw string) by data.startsWith('{'). One character. If the body starts with {, it's treated as JSON; otherwise as a string. A form-encoded body that happens to start with { gets JSON.stringify'd in fetch and json= in Python — wrong content type, but valid syntax. A non-JSON string like {not json} becomes JSON.stringify({not json}), a syntax error. The heuristic reads shape, not content; it never parses the JSON to check. If your body is real JSON, fine. Otherwise edit the output.

Gotchas

  • JS fetch output isn't runnable as-is. It's const response = await fetch(...) at top level — no async wrapper. Paste it into a browser console and you get a syntax error. Wrap it in async function main() { ... } main();, or run it where top-level await is legal. The Python and PHP outputs run as printed.
  • Ruby and C# break on non-standard verbs. Ruby generates Net::HTTP::Post, Net::HTTP::Get — class lookups. PROPFIND becomes Net::HTTP::Propfind, which doesn't exist. C# does the same with HttpMethod.Propfind. Standard verbs work; anything else throws at runtime.
  • C# hardcodes application/json. The body becomes StringContent(data, Encoding.UTF8, "application/json") regardless of your Content-Type header or the body's shape. Form data, text, XML — all labelled JSON. Set the content type yourself.
  • Bearer tokens stay in headers. The parser detects Bearer and stores auth.bearer, but generators emit the original Authorization header, not a dedicated auth API. Fine — just don't expect .bearerAuth().

Summary

  • The converter outputs 14 languages (4 JS variants, 2 Python, plus PHP/Go/Ruby/Java/C#/Rust/Kotlin/Swift), not the three the FAQ names — pick the one your stack uses.
  • It's a regex parser, not a shell tokenizer: unquoted -H headers vanish, quotes inside values truncate them, and whitespace in JSON bodies is collapsed before generation.
  • Four flags silently disappear: -k (TLS verify comes back on), --compressed (no Accept-Encoding), -F (form data parsed, never emitted — data loss), and the absence of -L (no-follow flips to follow, because the guard checks === false not falsy).
  • The JSON-vs-string choice is data.startsWith('{') — one character, shape not content. Edit the output for non-JSON bodies.
  • JS fetch output is await at top level — wrap it in an async function before running. Ruby/C# break on non-standard verbs; C# hardcodes application/json content type.
  • Convert in the cURL to Code Converter. To test the request live: API Tester. To inspect headers: HTTP Headers Parser. For turning a response into types: JSON to TypeScript. For a different conversion direction: SQL to MongoDB.