Convert a curl command to code

Paste any curl command — including one copied straight out of your browser's network tab with "Copy as cURL" — and get the same request written out in nine languages. The command is parsed in the page: method, URL, headers and body are read out of it and then re-rendered, so what comes back is the request you pasted rather than a template with your URL dropped into it.

Worked example

This command:

curl -X POST 'https://funapi.dev/api/friends/v1/characters' \
  -H 'Authorization: Bearer qa-admin-token' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Gunther","job":"Head barista"}'

is parsed as POST https://funapi.dev/api/friends/v1/characters with 2 header(s) and a 39-byte body, and converts to:

JavaScript (fetch)

const res = await fetch("https://funapi.dev/api/friends/v1/characters", {
  method: "POST",
  headers: {
    "Authorization": "Bearer qa-admin-token",
    "Content-Type": "application/json"
  },
  body: "{\"name\":\"Gunther\",\"job\":\"Head barista\"}"
});
console.log(res.status, await res.json());

JavaScript (axios)

import axios from 'axios';

const res = await axios({
  method: "post",
  url: "https://funapi.dev/api/friends/v1/characters",
  headers: {
    "Authorization": "Bearer qa-admin-token",
    "Content-Type": "application/json"
  },
  data: {"name":"Gunther","job":"Head barista"}
});
console.log(res.status, res.data);

Python (requests)

import requests

url = "https://funapi.dev/api/friends/v1/characters"
headers = {
    "Authorization": "Bearer qa-admin-token",
    "Content-Type": "application/json"
}
payload = {"name":"Gunther","job":"Head barista"}

res = requests.post(url, headers=headers, json=payload)
print(res.status_code, res.json())

Go (net/http)

package main

import (
	"fmt"
	"io"
	"net/http"
	"strings"
)

func main() {
	req, _ := http.NewRequest("POST", "https://funapi.dev/api/friends/v1/characters", strings.NewReader("{\"name\":\"Gunther\",\"job\":\"Head barista\"}"))
	req.Header.Set("Authorization", "Bearer qa-admin-token")
	req.Header.Set("Content-Type", "application/json")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	fmt.Println(res.StatusCode, string(out))
}

C# (HttpClient)

using var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, "https://funapi.dev/api/friends/v1/characters");
req.Headers.TryAddWithoutValidation("Authorization", "Bearer qa-admin-token");
req.Content = new StringContent("{\"name\":\"Gunther\",\"job\":\"Head barista\"}", Encoding.UTF8, "application/json");
var res = await client.SendAsync(req);
Console.WriteLine((int)res.StatusCode);
Console.WriteLine(await res.Content.ReadAsStringAsync());

Java (RestAssured)

given()
    .header("Authorization", "Bearer qa-admin-token")
    .header("Content-Type", "application/json")
    .body("{\"name\":\"Gunther\",\"job\":\"Head barista\"}")
.when()
    .post("https://funapi.dev/api/friends/v1/characters")
.then()
    .statusCode(200);

Playwright

import { test, expect } from '@playwright/test';

test('POST request', async ({ request }) => {
  const res = await request.post("https://funapi.dev/api/friends/v1/characters", {
  headers: {
    "Authorization": "Bearer qa-admin-token",
    "Content-Type": "application/json"
  },
  data: {"name":"Gunther","job":"Head barista"}
});
  expect(res.status()).toBe(200);
});

k6

import http from 'k6/http';
import { check } from 'k6';

export default function () {
  const res = http.request("POST", "https://funapi.dev/api/friends/v1/characters", "{\"name\":\"Gunther\",\"job\":\"Head barista\"}", { headers: {
    "Authorization": "Bearer qa-admin-token",
    "Content-Type": "application/json"
  } });
  check(res, { 'status is 200': r => r.status === 200 });
}

HTTPie

echo "{\"name\":\"Gunther\",\"job\":\"Head barista\"}" | http POST "https://funapi.dev/api/friends/v1/characters" Authorization:"Bearer qa-admin-token" Content-Type:"application/json"

What it handles

Backslash line continuations and the caret form cmd.exe uses, single and double quoting with escapes, repeated -H headers, repeated -d bodies joined the way curl joins them, -u basic auth normalised into an Authorization header, and the pile of flags a devtools copy brings along (--compressed, -s, -L, --max-time and friends), which are recognised and dropped rather than mistaken for the URL.

The two things it makes explicit

curl defaults to POST when you give it a body and no method, and it sets a content type you never wrote. Every other client in the list does neither. Both are therefore made explicit in the output — an inferred POST and an inferred Content-Type — because the most common way a converted request stops working is that the implicit half of the curl command did not come with it.

When it refuses

An unknown flag that might take a value stops the conversion instead of being skipped, because skipping it would swallow the URL that followed it and produce a plausible, wrong result. An unbalanced quote does the same. A converter that fails loudly is worth more than one that guesses.

Related

Other tools

All tools · Getting started guide · All 39 mock REST APIs