---
title: "curl Test Patterns Cheatsheet"
slug: "curl-test-patterns"
category: "cheatsheets"
tags: ["cheatsheets", "curl", "http", "api", "testing", "cli", "rest"]
status: "stable"
last_updated: 2026-05-14
summary: "curl recipes for GET, POST, PUT, DELETE, JSON bodies, auth headers, file uploads, and response inspection. The flags that matter for API testing."
related:
  [
    "[[cheatsheets/curl-flags]]",
    "[[cheatsheets/http-status-codes]]",
    "[[cheatsheets/json-jq-recipes]]",
    "[[cheatsheets/bash-one-liners]]",
    "[[backend/fastapi]]",
    "[[cheatsheets/openssl-commands]]",
    "[[cheatsheets/index|Cheatsheets]]",
  ]
---

## Overview

`curl` is the fastest tool for manually testing HTTP endpoints before writing client code. This card collects the invocations for the most common API testing scenarios: CRUD operations, JSON payloads, authentication, file uploads, and response inspection. For the full flag reference see [[cheatsheets/curl-flags]]; for parsing JSON responses see [[cheatsheets/json-jq-recipes]].

## GET requests

| Pattern | Command | Notes |
|---|---|---|
| Basic GET | `curl https://api.example.com/items` | Outputs body to stdout |
| With query params | `curl "https://api.example.com/items?page=2&limit=10"` | Quote the URL to prevent shell expansion of `&` |
| Follow redirects | `curl -L https://example.com` | Follows 3xx chains |
| Save to file | `curl -o out.json https://api.example.com/data` | Named output file |
| Show response headers | `curl -I https://api.example.com/items` | HEAD request only |
| Show headers + body | `curl -D - https://api.example.com/items` | `-D -` prints headers to stdout before body |
| Timing breakdown | `curl -w "@curl-format.txt" -s -o /dev/null https://example.com` | Custom format for DNS, connect, TTFB |
| Verbose | `curl -v https://api.example.com/items` | Shows request + response headers and TLS handshake |
| Silent + fail | `curl -sf https://api.example.com/items` | No progress; exit code 22 on HTTP error |

For API testing, combine `-s` (silent) and `-S` (show errors) to suppress progress but not hide curl errors.

## POST and PUT with JSON

| Pattern | Command | Notes |
|---|---|---|
| POST JSON inline | `curl -X POST https://api.example.com/items -H "Content-Type: application/json" -d '{"name":"foo"}'` | Single-line JSON body |
| POST JSON from file | `curl -X POST https://api.example.com/items -H "Content-Type: application/json" -d @payload.json` | `@` reads from file |
| PUT update | `curl -X PUT https://api.example.com/items/42 -H "Content-Type: application/json" -d '{"name":"bar"}'` | Replace resource |
| PATCH partial | `curl -X PATCH https://api.example.com/items/42 -H "Content-Type: application/json" -d '{"status":"active"}'` | Partial update |
| DELETE | `curl -X DELETE https://api.example.com/items/42` | No body required |
| Accept header | `curl https://api.example.com/items -H "Accept: application/json"` | Request specific format |
| Multiple headers | `curl ... -H "Content-Type: application/json" -H "X-Request-ID: abc123"` | Repeat `-H` for each |

`-d` sets method to POST implicitly; add `-X POST` explicitly for clarity in scripts.

## Authentication patterns

| Auth type | Command | Notes |
|---|---|---|
| Bearer token | `curl -H "Authorization: Bearer $TOKEN" https://api.example.com/protected` | Standard JWT or OAuth |
| Basic auth | `curl -u username:password https://api.example.com/resource` | URL-encodes credentials |
| Basic auth (prompt) | `curl -u username https://api.example.com/resource` | Prompts for password |
| API key header | `curl -H "X-API-Key: $API_KEY" https://api.example.com/resource` | Key name varies by service |
| API key query param | `curl "https://api.example.com/resource?api_key=$API_KEY"` | Less secure; logged in URLs |
| Client certificate | `curl --cert client.crt --key client.key https://api.example.com/resource` | mTLS |
| Cookie jar | `curl -c cookies.txt -b cookies.txt https://api.example.com/login` | Save and send cookies |
| Digest auth | `curl --digest -u user:pass https://api.example.com/resource` | Challenge-response |

Store tokens in environment variables, not inline. `export TOKEN=$(cat ~/.tokens/myapi)`.

## File uploads and multipart

| Pattern | Command | Notes |
|---|---|---|
| Single file upload | `curl -F "file=@photo.jpg" https://api.example.com/upload` | Multipart form |
| File + field | `curl -F "file=@photo.jpg" -F "title=My Photo" https://api.example.com/upload` | Mix file and fields |
| File with MIME type | `curl -F "file=@data.csv;type=text/csv" https://api.example.com/upload` | Override detected type |
| Binary body (PUT) | `curl -X PUT --data-binary @image.png -H "Content-Type: image/png" https://api.example.com/images/1` | Raw binary, no multipart |
| URL-encoded form | `curl -d "name=foo&value=bar" https://api.example.com/form` | `application/x-www-form-urlencoded` |

`-F` triggers `multipart/form-data`; `-d` triggers `application/x-www-form-urlencoded`. JSON bodies need `-H "Content-Type: application/json"` explicitly.

## Response inspection and scripting

| Pattern | Command | Notes |
|---|---|---|
| HTTP status code only | `curl -s -o /dev/null -w "%{http_code}" https://api.example.com/items` | Useful in scripts |
| Pretty-print JSON | `curl -s https://api.example.com/items \| jq .` | Pipe to jq |
| Extract field | `curl -s https://api.example.com/item/1 \| jq '.name'` | Single field |
| Store in variable | `BODY=$(curl -s https://api.example.com/item/1)` | Capture for reuse |
| Retry on failure | `curl --retry 3 --retry-delay 2 https://api.example.com/items` | Transient error recovery |
| Timeout | `curl --max-time 10 https://api.example.com/items` | Abort after 10 seconds |
| Ignore TLS errors | `curl -k https://localhost:8443/items` | Dev only; never production |
| Proxy | `curl -x http://proxy:3128 https://api.example.com/items` | HTTP proxy |

Chain curl with jq for lightweight API scripting: `curl -sf https://api.example.com/users | jq '.[].email'` dumps all emails.

## Common gotchas

- Single quotes around `{}` in shell: `'{"key":"val"}'` is safe; double quotes require escaping internal quotes.
- `-d @file` reads the file as-is, including newlines. Minify JSON before sending if the API is picky.
- `curl` exits 0 on HTTP 4xx/5xx unless you pass `-f`/`--fail`. Scripts that check only `$?` miss server errors.
- `--compressed` enables `Accept-Encoding: gzip` and decompresses the response automatically. Without it, a gzip response prints binary garbage.
- Redirect following (`-L`) may change the method from POST to GET on a 302. Use `--post301` and `--post302` to preserve POST.
- `-u user:pass` appears in process listing on Linux. Prefer `-H "Authorization: Basic $(echo -n user:pass | base64)"` in automated scripts.

## Related

- [[cheatsheets/curl-flags]]
- [[cheatsheets/http-status-codes]]
- [[cheatsheets/json-jq-recipes]]
- [[cheatsheets/bash-one-liners]]
- [[backend/fastapi]]
- [[cheatsheets/openssl-commands]]
- [[cheatsheets/index|Cheatsheets]]
