DevToolsmith

cURL to Go Converter

Convert curl commands to Go code that uses net/http from the standard library. Headers, JSON and form bodies, multipart file uploads, basic auth, proxies, -k and timeouts are converted into a complete program that compiles as is.

Runs 100% in your browser — nothing is uploaded

curl command
Tip: drop a file here236 chars · 236 bytes · 4 lines
Go · net/http
688 chars · 688 bytes · 32 lines
Parsed request

POST https://api.example.com/v1/orders?notify=true

  • Authorization: Bearer YOUR_API_TOKEN
  • Content-Type: application/json
  • Body: JSON

Example

curl
curl -X POST https://api.example.com/v1/events \
  -H 'Content-Type: application/json' \
  -H 'X-Api-Key: YOUR_KEY' \
  -d '{"type": "signup", "user_id": 42}' \
  -m 5
Go (net/http)
package main

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

func main() {
	client := &http.Client{
		Timeout: 5 * time.Second,
	}
	var data = strings.NewReader(`{"type": "signup", "user_id": 42}`)
	req, err := http.NewRequest("POST", "https://api.example.com/v1/events", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Api-Key", "YOUR_KEY")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(resp.Status)
	fmt.Printf("%s\n", bodyText)
}

curl options in net/http

curlGo
-XFirst argument of http.NewRequest
-Hreq.Header.Set(…), or Add for repeated headers
-dstrings.NewReader(body) as the request body
-Fmime/multipart writer, with writer.FormDataContentType() as Content-Type
-T file, --data-binary @fileos.Open(path) as the body
-u user:passreq.SetBasicAuth(user, pass)
-k&http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
-x proxyTransport.Proxy = http.ProxyURL(u) (or http.ProxyFromEnvironment)
-m 5http.Client{Timeout: 5 * time.Second}
-LDefault (up to 10 redirects; change with CheckRedirect)
--compressedDefault (the transport requests and decodes gzip)

Create one http.Client and reuse it for all requests: it holds the connection pool. A new client per request works but opens a new connection each time. For the response body, generate Go structs with JSON to Go.

Frequently asked questions

Does the generated Go code compile?

Yes. It is a complete main package that uses only the standard library, and our tests compile it with go vet and run it against a local server to check the request matches curl’s. Paste it into main.go and run go run main.go.

Why use http.NewRequest instead of http.Post?

http.Get and http.Post can’t set custom headers, and they use http.DefaultClient, which has no timeout. NewRequest plus client.Do works for every method, header and body, so the same pattern covers all curl commands.

Does Go’s HTTP client have a timeout?

Not by default: http.DefaultClient and &http.Client{} wait forever. The converter sets Timeout when curl had -m. In real code, always set one, or pass a context with a deadline using http.NewRequestWithContext.

Why does the code close resp.Body?

If the body isn’t read to the end and closed, the underlying TCP connection can’t be reused and leaks. defer resp.Body.Close() right after the error check is the standard idiom, even if you don’t need the body.

How do I decode the JSON response into a struct?

Replace io.ReadAll with json.NewDecoder(resp.Body).Decode(&result), where result is a struct matching the response. Paste a sample response into the JSON to Go converter to generate the struct with the right json tags.