|
1 | 1 | --- |
2 | 2 | name: api-request |
3 | | -description: Send HTTP API requests using curl. Use when the user asks to call an API, fetch a URL, send POST/PUT/DELETE requests, or work with REST endpoints and JSON payloads. |
4 | | -compatibility: Requires curl |
| 3 | +description: >- |
| 4 | + Send HTTP API requests using curl. Use when the user asks to call an API, |
| 5 | + fetch data from a URL, send POST/PUT/PATCH/DELETE requests, work with REST |
| 6 | + or GraphQL endpoints, upload files, authenticate with Bearer tokens or API |
| 7 | + keys, debug HTTP responses, or interact with any web service via HTTP. |
| 8 | +license: MIT |
| 9 | +compatibility: Requires curl (pre-installed on macOS and most Linux distributions) |
| 10 | +metadata: |
| 11 | + author: zeph |
| 12 | + version: "1.0" |
5 | 13 | --- |
6 | | -# API Requests |
7 | 14 |
|
8 | | -## GET request |
| 15 | +# HTTP API Requests with curl |
| 16 | + |
| 17 | +## Quick Reference |
| 18 | + |
| 19 | +| Action | Command | |
| 20 | +|--------|---------| |
| 21 | +| GET | `curl -s URL` | |
| 22 | +| POST JSON | `curl -s -X POST -H "Content-Type: application/json" -d '{}' URL` | |
| 23 | +| PUT | `curl -s -X PUT -H "Content-Type: application/json" -d '{}' URL` | |
| 24 | +| PATCH | `curl -s -X PATCH -H "Content-Type: application/json" -d '{}' URL` | |
| 25 | +| DELETE | `curl -s -X DELETE URL` | |
| 26 | +| HEAD | `curl -s -I URL` | |
| 27 | + |
| 28 | +## Essential Options |
| 29 | + |
| 30 | +| Option | Long form | Purpose | |
| 31 | +|--------|-----------|---------| |
| 32 | +| `-s` | `--silent` | Suppress progress bar (always use for scripting) | |
| 33 | +| `-S` | `--show-error` | Show errors even when silent | |
| 34 | +| `-X` | `--request` | HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) | |
| 35 | +| `-H` | `--header` | Add request header (`-H "Name: Value"`) | |
| 36 | +| `-d` | `--data` | Send request body (implies POST) | |
| 37 | +| `-o` | `--output` | Write response body to file | |
| 38 | +| `-w` | `--write-out` | Print metadata after transfer (status code, timing) | |
| 39 | +| `-L` | `--location` | Follow HTTP redirects (3xx) | |
| 40 | +| `-i` | `--include` | Include response headers in output | |
| 41 | +| `-I` | `--head` | Fetch headers only (HEAD request) | |
| 42 | +| `-k` | `--insecure` | Skip TLS certificate verification | |
| 43 | +| `-v` | `--verbose` | Show full request/response exchange for debugging | |
| 44 | +| `-f` | `--fail` | Return exit code 22 on HTTP errors (4xx/5xx) | |
| 45 | +| `-F` | `--form` | Multipart form field (implies POST, multipart/form-data) | |
| 46 | +| `-u` | `--user` | Basic auth credentials (`user:password`) | |
| 47 | + |
| 48 | +## Timeouts |
| 49 | + |
9 | 50 | ```bash |
10 | | -curl -s URL |
| 51 | +# Connection timeout (seconds to establish TCP connection) |
| 52 | +curl -s --connect-timeout 10 URL |
| 53 | + |
| 54 | +# Max total time (entire operation including transfer) |
| 55 | +curl -s --max-time 30 URL |
| 56 | + |
| 57 | +# Both together (recommended for robustness) |
| 58 | +curl -sS --connect-timeout 10 --max-time 30 URL |
11 | 59 | ``` |
12 | 60 |
|
13 | | -## POST JSON |
| 61 | +## GET Requests |
| 62 | + |
14 | 63 | ```bash |
15 | | -curl -s -X POST -H "Content-Type: application/json" -d '{"key":"value"}' URL |
| 64 | +# Simple GET |
| 65 | +curl -s "https://api.example.com/users" |
| 66 | + |
| 67 | +# With query parameters (URL-encode special characters) |
| 68 | +curl -s "https://api.example.com/users?status=active&limit=10" |
| 69 | + |
| 70 | +# Follow redirects |
| 71 | +curl -sL "https://example.com/redirect" |
| 72 | + |
| 73 | +# Save response to file |
| 74 | +curl -sS -o response.json "https://api.example.com/data" |
16 | 75 | ``` |
17 | 76 |
|
18 | | -## With headers |
| 77 | +## POST Requests |
| 78 | + |
19 | 79 | ```bash |
20 | | -curl -s -H "Authorization: Bearer TOKEN" URL |
| 80 | +# JSON body (most common for REST APIs) |
| 81 | +curl -s -X POST \ |
| 82 | + -H "Content-Type: application/json" \ |
| 83 | + -d '{"name": "Alice", "email": "[email protected]"}' \ |
| 84 | + "https://api.example.com/users" |
| 85 | + |
| 86 | +# JSON body from file |
| 87 | +curl -s -X POST \ |
| 88 | + -H "Content-Type: application/json" \ |
| 89 | + -d @payload.json \ |
| 90 | + "https://api.example.com/users" |
| 91 | + |
| 92 | +# URL-encoded form data |
| 93 | +curl -s -X POST \ |
| 94 | + -d "username=alice&password=secret" \ |
| 95 | + "https://api.example.com/login" |
| 96 | + |
| 97 | +# Empty POST (some APIs require POST with no body) |
| 98 | +curl -s -X POST "https://api.example.com/trigger" |
21 | 99 | ``` |
22 | 100 |
|
23 | | -## Response with status code |
| 101 | +## PUT and PATCH |
| 102 | + |
24 | 103 | ```bash |
25 | | -curl -s -o /dev/null -w "%{http_code}" URL |
| 104 | +# PUT — full resource replacement |
| 105 | +curl -s -X PUT \ |
| 106 | + -H "Content-Type: application/json" \ |
| 107 | + -d '{"name": "Alice", "email": "[email protected]", "role": "admin"}' \ |
| 108 | + "https://api.example.com/users/42" |
| 109 | + |
| 110 | +# PATCH — partial update |
| 111 | +curl -s -X PATCH \ |
| 112 | + -H "Content-Type: application/json" \ |
| 113 | + -d '{"email": "[email protected]"}' \ |
| 114 | + "https://api.example.com/users/42" |
| 115 | +``` |
| 116 | + |
| 117 | +## DELETE |
| 118 | + |
| 119 | +```bash |
| 120 | +# Simple DELETE |
| 121 | +curl -s -X DELETE "https://api.example.com/users/42" |
| 122 | + |
| 123 | +# DELETE with body (some APIs require it) |
| 124 | +curl -s -X DELETE \ |
| 125 | + -H "Content-Type: application/json" \ |
| 126 | + -d '{"reason": "duplicate"}' \ |
| 127 | + "https://api.example.com/users/42" |
| 128 | +``` |
| 129 | + |
| 130 | +## Authentication |
| 131 | + |
| 132 | +```bash |
| 133 | +# Bearer token (OAuth2, JWT) |
| 134 | +curl -s -H "Authorization: Bearer eyJhbGciOi..." "https://api.example.com/me" |
| 135 | + |
| 136 | +# API key in header |
| 137 | +curl -s -H "X-API-Key: abc123" "https://api.example.com/data" |
| 138 | + |
| 139 | +# API key as query parameter |
| 140 | +curl -s "https://api.example.com/data?api_key=abc123" |
| 141 | + |
| 142 | +# Basic auth (user:password) |
| 143 | +curl -s -u "admin:secret" "https://api.example.com/admin" |
| 144 | + |
| 145 | +# Basic auth with prompt for password (interactive) |
| 146 | +curl -s -u "admin" "https://api.example.com/admin" |
| 147 | +``` |
| 148 | + |
| 149 | +## File Upload |
| 150 | + |
| 151 | +```bash |
| 152 | +# Single file upload (multipart/form-data) |
| 153 | +curl -s -F "file=@/path/to/document.pdf" "https://api.example.com/upload" |
| 154 | + |
| 155 | +# File with explicit content type |
| 156 | +curl -s -F "[email protected];type=image/jpeg" "https://api.example.com/upload" |
| 157 | + |
| 158 | +# File with additional form fields |
| 159 | +curl -s \ |
| 160 | + |
| 161 | + -F "title=Q4 Report" \ |
| 162 | + -F "category=finance" \ |
| 163 | + "https://api.example.com/documents" |
| 164 | + |
| 165 | +# Multiple files |
| 166 | +curl -s \ |
| 167 | + |
| 168 | + |
| 169 | + "https://api.example.com/batch-upload" |
| 170 | + |
| 171 | +# Raw binary upload (PUT) |
| 172 | +curl -s -X PUT \ |
| 173 | + -H "Content-Type: application/octet-stream" \ |
| 174 | + --data-binary @image.png \ |
| 175 | + "https://api.example.com/files/image.png" |
26 | 176 | ``` |
| 177 | + |
| 178 | +## Response Handling |
| 179 | + |
| 180 | +```bash |
| 181 | +# Get HTTP status code only |
| 182 | +curl -s -o /dev/null -w "%{http_code}" "https://api.example.com/health" |
| 183 | + |
| 184 | +# Get status code + response body |
| 185 | +curl -s -w "\n%{http_code}" "https://api.example.com/users" |
| 186 | + |
| 187 | +# Get response headers + body |
| 188 | +curl -si "https://api.example.com/users" |
| 189 | + |
| 190 | +# Detailed timing info |
| 191 | +curl -s -o /dev/null -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\nStatus: %{http_code}\n" "https://api.example.com" |
| 192 | + |
| 193 | +# Pretty-print JSON response (pipe to jq) |
| 194 | +curl -s "https://api.example.com/users" | jq . |
| 195 | + |
| 196 | +# Extract specific field from JSON |
| 197 | +curl -s "https://api.example.com/users/1" | jq -r '.email' |
| 198 | + |
| 199 | +# Response headers only |
| 200 | +curl -sI "https://api.example.com/users" |
| 201 | +``` |
| 202 | + |
| 203 | +## Common Patterns |
| 204 | + |
| 205 | +### Pagination |
| 206 | +```bash |
| 207 | +# Offset-based |
| 208 | +curl -s "https://api.example.com/items?offset=0&limit=50" |
| 209 | +curl -s "https://api.example.com/items?offset=50&limit=50" |
| 210 | + |
| 211 | +# Page-based |
| 212 | +curl -s "https://api.example.com/items?page=1&per_page=25" |
| 213 | + |
| 214 | +# Cursor-based (use cursor from previous response) |
| 215 | +curl -s "https://api.example.com/items?cursor=eyJpZCI6MTAwfQ" |
| 216 | +``` |
| 217 | + |
| 218 | +### Retry on Failure |
| 219 | +```bash |
| 220 | +# Retry up to 3 times with exponential backoff |
| 221 | +curl -s --retry 3 --retry-delay 2 --retry-max-time 30 "https://api.example.com/data" |
| 222 | + |
| 223 | +# Retry only on specific errors (transient) |
| 224 | +curl -s --retry 3 --retry-all-errors "https://api.example.com/data" |
| 225 | +``` |
| 226 | + |
| 227 | +### Conditional Requests |
| 228 | +```bash |
| 229 | +# If-Modified-Since (returns 304 if unchanged) |
| 230 | +curl -s -H "If-Modified-Since: Mon, 01 Jan 2024 00:00:00 GMT" "https://api.example.com/data" |
| 231 | + |
| 232 | +# ETag-based caching |
| 233 | +curl -s -H 'If-None-Match: "abc123"' "https://api.example.com/data" |
| 234 | +``` |
| 235 | + |
| 236 | +### GraphQL |
| 237 | +```bash |
| 238 | +curl -s -X POST \ |
| 239 | + -H "Content-Type: application/json" \ |
| 240 | + -d '{"query": "{ users(first: 10) { id name email } }"}' \ |
| 241 | + "https://api.example.com/graphql" |
| 242 | +``` |
| 243 | + |
| 244 | +## Debugging |
| 245 | + |
| 246 | +```bash |
| 247 | +# Verbose output (shows full request/response headers and TLS handshake) |
| 248 | +curl -v "https://api.example.com/users" 2>&1 |
| 249 | + |
| 250 | +# Trace to file (hex dump of all data) |
| 251 | +curl --trace trace.log "https://api.example.com/users" |
| 252 | + |
| 253 | +# Show only response headers |
| 254 | +curl -sI "https://api.example.com/users" |
| 255 | + |
| 256 | +# Dump request and response headers to file |
| 257 | +curl -sS -D headers.txt -o body.json "https://api.example.com/users" |
| 258 | +``` |
| 259 | + |
| 260 | +## HTTP Status Code Reference |
| 261 | + |
| 262 | +| Range | Meaning | Common Codes | |
| 263 | +|-------|---------|-------------| |
| 264 | +| 2xx | Success | 200 OK, 201 Created, 204 No Content | |
| 265 | +| 3xx | Redirect | 301 Moved, 302 Found, 304 Not Modified | |
| 266 | +| 4xx | Client error | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable, 429 Too Many Requests | |
| 267 | +| 5xx | Server error | 500 Internal Error, 502 Bad Gateway, 503 Unavailable, 504 Timeout | |
| 268 | + |
| 269 | +## Important Notes |
| 270 | + |
| 271 | +- Always use `-s` (silent) to suppress the progress bar in scripts |
| 272 | +- Use `-sS` to suppress progress but still show errors |
| 273 | +- When sending JSON, always set `-H "Content-Type: application/json"` |
| 274 | +- Use `-L` to follow redirects (curl does not follow them by default) |
| 275 | +- Use `--connect-timeout` and `--max-time` for robustness against hanging requests |
| 276 | +- Pipe to `jq .` for readable JSON output, or `jq -r '.field'` to extract values |
| 277 | +- Use `-f` (fail) when you need curl to return a non-zero exit code on HTTP errors |
| 278 | +- For binary data in POST body, use `--data-binary` instead of `-d` (which strips newlines) |
| 279 | +- Special characters in URLs should be percent-encoded (spaces = `%20`, `&` = `%26`) |
| 280 | +- Use single quotes around JSON payloads to avoid shell variable expansion issues |
0 commit comments