curl is the universal HTTP client available on virtually every system. This guide covers everything you need to test REST APIs effectively: all HTTP methods, authentication, file uploads, cookie handling, response inspection, and scripted API tests.
| Flag | Purpose |
|---|---|
| -s | Silent mode (suppress progress bar) |
| -v | Verbose: show request and response headers |
| -i | Include response headers in output |
| -o file | Save response to file |
| -X METHOD | Set HTTP method (GET, POST, PUT, DELETE, PATCH) |
| -H "Header: Value" | Set a request header |
| -d '{...}' | Request body (raw data) |
| -F field=value | Form data (multipart) |
| -u user:pass | Basic authentication |
| -L | Follow redirects |
| -k | Skip SSL verification (dev only) |
| -w "%{http_code}" | Print response code after request |
# Basic GET request
curl -s https://jsonplaceholder.typicode.com/posts/1 | jq .
# GET with query parameters
curl -sG https://api.example.com/search \
--data-urlencode "q=bash scripting" \
--data-urlencode "limit=10" | jq .
# GET and show only the HTTP status code
curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health
# POST JSON body
curl -s -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{
"name": "Alice",
"email": "alice@example.com",
"role": "admin"
}' | jq .
# POST from a JSON file
curl -s -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d @user.json | jq .
# Full update with PUT
curl -s -X PUT https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"name": "Alice Smith", "email": "alice@example.com"}'
# Partial update with PATCH
curl -s -X PATCH https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"name": "Alice Smith"}'
curl -s -X DELETE https://api.example.com/users/123
curl -s -o /dev/null -w "%{http_code}" -X DELETE https://api.example.com/posts/5
# Should print 204 for success
TOKEN="eyJhbGciOiJIUzI1NiJ9..."
curl -s https://api.example.com/me \
-H "Authorization: Bearer ${TOKEN}" | jq .
curl -s https://api.example.com/data \
-H "X-API-Key: your-api-key-here" | jq .
# curl handles the Base64 encoding automatically with -u
curl -s -u "admin:password" https://api.example.com/admin/stats
# Login and save session cookie to file
curl -s -c cookies.txt -X POST https://api.example.com/login \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "password": "secret"}'
# Use saved cookie for subsequent requests
curl -s -b cookies.txt https://api.example.com/dashboard | jq .
# Upload a single file (multipart form)
curl -s -X POST https://api.example.com/upload \
-F "file=@/path/to/image.jpg" \
-F "description=Profile photo"
# Upload raw binary (Content-Type: application/octet-stream)
curl -s -X PUT https://api.example.com/storage/file.pdf \
-H "Content-Type: application/pdf" \
--data-binary @document.pdf
# Show full request and response headers
curl -v https://api.example.com/users 2>&1 | head -40
# Show only response headers
curl -si https://api.example.com/users | head -20
# Measure timing breakdown
curl -s -o /dev/null -w "
DNS: %{time_namelookup}s
Connect: %{time_connect}s
SSL: %{time_appconnect}s
TTFB: %{time_starttransfer}s
Total: %{time_total}s
" https://api.example.com/users
#!/usr/bin/env bash
set -euo pipefail
BASE_URL="https://api.example.com"
TOKEN="your-token-here"
PASS=0; FAIL=0
assert_status() {
local desc="$1" expected="$2" actual="$3"
if [ "${actual}" = "${expected}" ]; then
echo "✅ ${desc}"
((PASS++))
else
echo "❌ ${desc} (expected ${expected}, got ${actual})"
((FAIL++))
fi
}
# Test 1: Health check
status=$(curl -s -o /dev/null -w "%{http_code}" "${BASE_URL}/health")
assert_status "GET /health returns 200" "200" "${status}"
# Test 2: Authenticated endpoint
status=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer ${TOKEN}" \
"${BASE_URL}/me")
assert_status "GET /me returns 200 with token" "200" "${status}"
# Test 3: Unauthenticated request rejected
status=$(curl -s -o /dev/null -w "%{http_code}" "${BASE_URL}/me")
assert_status "GET /me returns 401 without token" "401" "${status}"
echo ""
echo "Results: ${PASS} passed, ${FAIL} failed"