~$ delxium

curl · http · api

curl: A Pocket Companion

Talk to any HTTP API from the terminal — GET, POST JSON, auth, and the flags that make debugging obvious.

curl is how you talk to the web from the command line — test an endpoint, reproduce a bug, script a deploy, or poke at someone’s API before writing a line of code. This guide covers the moves that come up daily, using the kind of JSON API you’d build with our Docker pocket companion.

$ curl https://api.example.com/health
{"status":"ok"}

Seeing what’s really happening

A plain curl URL prints the response body. The flags that make it useful:

$ curl -i https://api.example.com/health   # include response headers
$ curl -s https://api.example.com/health   # silent — no progress meter
$ curl -v https://api.example.com/health   # verbose — show the full request + response
$ curl -o out.json https://...             # write body to a file
$ curl -L https://example.com              # follow redirects (301/302)

The everyday combo: -s and -i

-s hides curl’s progress bar (essential when piping to jq); -i shows the status line and headers so you can see what came back, not just the body. -v is the big hammer when something’s wrong — it prints the exact bytes sent and received.

Methods and data

# GET is the default. Be explicit with -X for others.
$ curl -X DELETE https://api.example.com/items/42

# POST form data
$ curl -d "name=Ada&role=admin" https://api.example.com/users

# POST JSON  set the header *and* send the body
$ curl -X POST https://api.example.com/users \
    -H "Content-Type: application/json" \
    -d '{"name":"Ada","role":"admin"}'

# send a JSON file as the body
$ curl -X POST https://api.example.com/import \
    -H "Content-Type: application/json" \
    -d @payload.json

JSON needs the Content-Type header

-d defaults to application/x-www-form-urlencoded. If you send JSON without -H "Content-Type: application/json", most APIs will reject it or mis-parse it. Set the header every time you send a JSON body.

Authentication

# Bearer token (most APIs)
$ curl -H "Authorization: Bearer $TOKEN" https://api.example.com/me

# Basic auth
$ curl -u username:password https://api.example.com/private

# an API key in a header
$ curl -H "X-API-Key: $KEY" https://api.example.com/data

A real login-then-use flow, exactly how you’d test an admin API:

$ TOKEN=$(curl -s -X POST https://api.example.com/login \
    -H "Content-Type: application/json" \
    -d '{"email":"me@x.com","password":"secret"}' | jq -r .access_token)

$ curl -s -H "Authorization: Bearer $TOKEN" https://api.example.com/me

(That jq -r .access_token pulls one field out of the JSON response — see the regex and JSON guides for more on slicing output.)

Uploads and downloads

# upload a file as multipart/form-data (note the @)
$ curl -F "file=@cover.png;type=image/png" https://api.example.com/uploads

# download, keeping the remote filename, resuming if interrupted
$ curl -O -C - https://example.com/big.iso

Inspecting and timing

# headers only (a HEAD request)
$ curl -I https://example.com

# just the HTTP status code (great for scripts / health checks)
$ curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/health

# where is the time going?
$ curl -s -o /dev/null -w "dns:%{time_namelookup} connect:%{time_connect} total:%{time_total}\n" https://example.com

The status-code one-liner is a tiny but mighty health check — 200 means up, anything else is worth a look.

Pretty-printing JSON

curl prints raw JSON; pipe it through jq to read it:

$ curl -s https://api.example.com/items | jq
$ curl -s https://api.example.com/items | jq '.[] | .name'   # just the names

When it breaks

Symptom Likely cause
curl: (6) Could not resolve host DNS / typo in the hostname.
curl: (7) Failed to connect Nothing listening on that host:port, or a firewall.
curl: (60) SSL certificate problem Bad/expired/self-signed cert. -k skips verification — for testing only.
Empty body but you expected JSON Add -i to see the status; you may be getting a 4xx/redirect.
JSON body rejected (400) Missing -H "Content-Type: application/json".

Pocket cheat-sheet

Do Command
GET with headers / silent / verbose curl -i URL / -s / -v
POST JSON curl -X POST URL -H "Content-Type: application/json" -d '{...}'
Bearer auth curl -H "Authorization: Bearer $T" URL
Body from file curl -d @file.json URL
Upload a file curl -F "file=@path" URL
Just the status code curl -s -o /dev/null -w "%{http_code}" URL
Follow redirects curl -L URL
Pretty JSON curl -s URL \| jq

Once curl is muscle memory you can exercise any API before writing code, reproduce a bug in one line, and drop health checks into any script. man curl lists the rest — there are hundreds of flags, but these are the ones you’ll actually use.

← all field notes