curl Mastery
Essential Flags
| Flag | Purpose | Example |
|---|---|---|
|
Silent (no progress) |
|
|
Show errors (with -s) |
|
|
Fail silently on HTTP errors |
|
|
Follow redirects |
|
|
Headers only (HEAD request) |
|
|
Include headers in output |
|
|
Verbose (debug) |
|
|
Output to file |
|
|
Save with remote filename |
|
|
Write-out format |
|
HTTP Methods
# GET (default)
curl -s https://api.example.com/users
# POST
curl -s -X POST https://api.example.com/users
# PUT
curl -s -X PUT https://api.example.com/users/1
# PATCH
curl -s -X PATCH https://api.example.com/users/1
# DELETE
curl -s -X DELETE https://api.example.com/users/1
Headers
# Single header
curl -s -H "Authorization: Bearer TOKEN" https://...
# Multiple headers
curl -s \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
https://...
# Custom headers
curl -s \
-H "X-Request-ID: $(uuidgen)" \
-H "X-Custom-Header: value" \
https://...
Sending Data
JSON Body
# Inline JSON
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"name": "John", "email": "john@example.com"}' \
https://api.example.com/users
# JSON from file
curl -s -X POST \
-H "Content-Type: application/json" \
-d @payload.json \
https://api.example.com/users
# JSON from stdin (heredoc)
curl -s -X POST \
-H "Content-Type: application/json" \
-d @- https://api.example.com/users <<'EOF'
{
"name": "John",
"email": "john@example.com"
}
EOF
Form Data
# URL-encoded form
curl -s -X POST \
-d "username=john&password=secret" \
https://api.example.com/login
# Multipart form (file upload)
curl -s -X POST \
-F "file=@document.pdf" \
-F "description=My file" \
https://api.example.com/upload
Query Parameters
# In URL (must quote for special chars)
curl -s "https://api.example.com/search?q=hello&limit=10"
# With --data-urlencode (auto-encodes)
curl -s -G \
--data-urlencode "q=hello world" \
--data-urlencode "filter=name:john" \
https://api.example.com/search
Authentication
# Bearer token
curl -s -H "Authorization: Bearer eyJhbGciOiJIUzI1..." https://...
# API key in header
curl -s -H "X-API-Key: your-api-key" https://...
# API key in query param
curl -s "https://api.example.com/data?api_key=your-key"
# Basic auth
curl -s -u "username:password" https://...
# Basic auth (explicit header)
curl -s -H "Authorization: Basic $(echo -n 'user:pass' | base64)" https://...
# Session cookie
curl -s -H "Cookie: session=abc123" https://...
# Cookie from file
curl -s -b cookies.txt https://...
# Save cookies to file
curl -s -c cookies.txt https://...
Response Handling
Status Code Only
# Get HTTP status code
curl -s -o /dev/null -w '%{http_code}' https://api.example.com/health
# Check if successful
if [[ $(curl -s -o /dev/null -w '%{http_code}' https://...) == "200" ]]; then
echo "OK"
fi
Response Time
# Time breakdown
curl -s -o /dev/null -w '
namelookup: %{time_namelookup}s
connect: %{time_connect}s
pretransfer: %{time_pretransfer}s
redirect: %{time_redirect}s
starttransfer: %{time_starttransfer}s
total: %{time_total}s
' https://api.example.com/
# Just total time
curl -s -o /dev/null -w '%{time_total}s\n' https://...
Save Response and Headers
# Response to file, headers to stderr
curl -sD - https://... > response.json
# Headers to file, response to stdout
curl -sD headers.txt https://... | jq
# Both to files
curl -s -D headers.txt -o response.json https://...
Practical Patterns
Retry on Failure
curl -s --retry 3 --retry-delay 2 https://...
Timeout
# Connection timeout
curl -s --connect-timeout 5 https://...
# Max time for entire operation
curl -s --max-time 30 https://...
Rate Limiting (loop with delay)
for id in 1 2 3 4 5; do
curl -s "https://api.example.com/users/$id" | jq -r '.email'
sleep 0.5 # Be nice to the API
done
Parallel Requests
# Using xargs
echo "1 2 3 4 5" | xargs -P 5 -n 1 -I {} \
curl -s "https://api.example.com/users/{}" -o "user_{}.json"
# Using GNU parallel
parallel -j 5 curl -s "https://api.example.com/users/{}" -o "user_{}.json" ::: 1 2 3 4 5
Error Handling
# Fail on HTTP error, capture response
response=$(curl -sf https://api.example.com/data) || {
echo "Request failed with exit code $?"
exit 1
}
echo "$response" | jq
curl + jq Combos
# Pretty print
curl -s https://... | jq
# Extract field
curl -s https://... | jq -r '.data.email'
# Filter array
curl -s https://... | jq '.users[] | select(.active)'
# Transform
curl -s https://... | jq '{id: .id, name: .name}'
# Count
curl -s https://... | jq '.items | length'
# First N items
curl -s https://... | jq '.items[:5]'
Pro Tips
Create curl Config File
# ~/.curlrc
silent
show-error
location
user-agent = "MyApp/1.0"
Alias for Common Patterns
# ~/.zshrc
alias curls='curl -sS'
alias curlj='curl -sS -H "Content-Type: application/json"'
alias curlv='curl -v'
Debug Mode
# See everything
curl -v --trace-ascii /dev/stderr https://...
# Just request/response
curl -v https://... 2>&1 | grep -E '^[<>]'
Exercises
-
Fetch a URL and output only the status code
-
POST JSON data and capture the response ID
-
Download a file with progress bar
-
Make 10 parallel requests and save each to a file
-
Implement retry logic for a flaky endpoint