Day 4 — API Testing with curl#
Goal: Use
curlto send HTTP requests from the terminal — GET, POST, headers, JSON bodies — so you can test and debug APIs without leaving the command line.
What Is curl?#
curl (Client URL) is a command-line tool for making HTTP requests. It comes pre-installed on most Linux systems.
curl --version
# curl 8.x.x ...Think of curl as a browser for your terminal — but instead of rendering a web page, it shows you the raw HTTP response.
Basic GET Request#
# The simplest curl command:
curl https://httpbin.org/getThis sends a GET request and prints the response body. httpbin.org is a free API for testing HTTP requests.
Useful flags for GET#
# Show response headers too (-i = include headers):
curl -i https://httpbin.org/get
# Show ONLY headers (-I = head request):
curl -I https://httpbin.org/get
# Silent mode — hide progress bar (-s):
curl -s https://httpbin.org/get
# Follow redirects (-L):
curl -L https://httpbin.org/redirect/1
# Show verbose debug info (-v):
curl -v https://httpbin.org/get🧠 Knowledge Check#
Q1: You want to see both the response body and the HTTP headers that the server sends back. Which curl flag should you use?
- A)
-v - B)
-i - C)
-I - D)
-s
Answer
B — -i includes the response headers in the output before the response body.
GET with Query Parameters#
Query parameters go after ? in the URL:
# Single parameter:
curl "https://httpbin.org/get?name=Alice"
# Multiple parameters (use & to separate):
curl "https://httpbin.org/get?name=Alice&role=student&course=TDS"Important: Always put the URL in quotes if it contains
&,?, or other special characters.
Setting Headers#
Use -H to add headers:
# Accept JSON:
curl -H "Accept: application/json" https://httpbin.org/get
# Multiple headers:
curl -H "Accept: application/json" \
-H "X-Custom-Header: hello" \
https://httpbin.org/headers
# Authorization header:
curl -H "Authorization: Bearer my-token-123" \
https://httpbin.org/bearerPOST Requests — Sending Data#
Sending JSON#
# POST with JSON body (-d = data, -X = method):
curl -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "age": 25}'Shorter way — POST is implied with -d#
# curl automatically uses POST when you provide -d:
curl https://httpbin.org/post \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "age": 25}'Sending form data#
# URL-encoded form data (like an HTML form):
curl -X POST https://httpbin.org/post \
-d "name=Alice&age=25"
# File upload:
curl -X POST https://httpbin.org/post \
-F "[email protected]"Reading data from a file#
# Create a JSON file:
echo '{"name": "Alice", "email": "[email protected]"}' > /tmp/user.json
# Send it:
curl -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-d @/tmp/user.json🧠 Knowledge Check#
Q1: What does the -d flag in curl do?
- A) Downloads a file
- B) Deletes a resource
- C) Sends data as the request body and automatically sets the method to POST
- D) Disables SSL verification
Answer
C — The -d (or --data) flag sends the specified data in the request body. When used, curl automatically assumes you want to make a POST request.
PUT, PATCH, DELETE Requests#
# PUT — replace a resource:
curl -X PUT https://httpbin.org/put \
-H "Content-Type: application/json" \
-d '{"name": "Alice Updated", "age": 26}'
# PATCH — partial update:
curl -X PATCH https://httpbin.org/patch \
-H "Content-Type: application/json" \
-d '{"age": 26}'
# DELETE — remove a resource:
curl -X DELETE https://httpbin.org/deleteWorking with the Response#
Saving response to a file#
# Save response body:
curl -s https://httpbin.org/get -o response.json
# Save to file named from URL:
curl -s -O https://example.com/data.csvPiping to other tools#
# Pretty-print JSON with jq:
curl -s https://httpbin.org/get | jq .
# Extract specific fields:
curl -s https://httpbin.org/get | jq '.headers."User-Agent"'
# Count response size:
curl -s https://httpbin.org/get | wc -c
# Search response:
curl -s https://httpbin.org/get | grep "origin"Getting just the status code#
# Output only the HTTP status code:
curl -s -o /dev/null -w "%{http_code}\n" https://httpbin.org/get
# 200
curl -s -o /dev/null -w "%{http_code}\n" https://httpbin.org/status/404
# 404Authentication with curl#
Basic auth#
curl -u "username:password" https://httpbin.org/basic-auth/username/passwordBearer token#
curl -H "Authorization: Bearer my-token-123" https://httpbin.org/bearerAPI key in header#
curl -H "X-API-Key: abc123" https://api.example.com/dataDebugging with -v (Verbose)#
The -v flag shows the full request and response:
curl -v https://httpbin.org/get* Trying 34.193.x.x:443...
* Connected to httpbin.org
> GET /get HTTP/2 ← request line
> Host: httpbin.org ← request headers
> User-Agent: curl/8.x.x
> Accept: */*
>
< HTTP/2 200 ← response status
< content-type: application/json ← response headers
< content-length: 256
<
{ ← response body
"args": {},
"headers": {...},
...
}Lines starting with > are what you sent. Lines starting with < are what the server returned.
curl Cheatsheet#
| Flag | What it does | Example |
|---|---|---|
-X METHOD | Set HTTP method | -X POST, -X DELETE |
-H "..." | Add a header | -H "Content-Type: application/json" |
-d '...' | Send data (body) | -d '{"key": "value"}' |
-d @file | Send data from file | -d @data.json |
-i | Include response headers | curl -i url |
-I | Headers only (HEAD request) | curl -I url |
-s | Silent (no progress bar) | curl -s url |
-v | Verbose (debug) | curl -v url |
-L | Follow redirects | curl -L url |
-o file | Save output to file | -o response.json |
-u user:pass | Basic authentication | -u admin:secret |
-w "format" | Custom output format | -w "%{http_code}" |
-F "key=val" | Form/file upload | -F "[email protected]" |
Q&A#
Q: What is the difference between -d and -F?
A:
-dsends data as the request body (typically JSON or form-encoded)-Fsends data asmultipart/form-data— used for file uploads
# -d: JSON data
curl -d '{"name": "Alice"}' -H "Content-Type: application/json" url
# -F: file upload
curl -F "[email protected]" -F "caption=My photo" urlQ: How do I send a POST with an empty body?
A:
curl -X POST https://api.example.com/action -d ''
# or:
curl -X POST https://api.example.com/action -H "Content-Length: 0"Q: How do I install jq for pretty-printing JSON?
A:
sudo apt install jq -y
# Now you can:
curl -s https://httpbin.org/get | jq . # pretty-print
curl -s https://httpbin.org/get | jq '.origin' # extract fieldjq is an essential tool for working with JSON on the command line.
Q: Can I use curl with HTTPS?
A: Yes, curl handles HTTPS by default. It verifies SSL certificates automatically. If you get certificate errors on a dev/test server, you can skip verification with -k (insecure — only for testing):
curl -k https://self-signed-server.local/apiExercises#
Exercise 1: Basic GET requests
# 1. Fetch your public IP:
curl -s https://httpbin.org/ip
# 2. Get just the status code of google.com:
curl -s -o /dev/null -w "%{http_code}\n" https://www.google.com
# 3. Get the headers of github.com:
curl -I https://github.comExpected results
# 1. Your IP in JSON:
{"origin": "your.ip.address"}
# 2. Status code (after redirects):
200
# 3. Response headers including:
HTTP/2 200
content-type: text/html; charset=utf-8
server: GitHub.com
...Exercise 2: POST with JSON
Send a POST request to httpbin with your name and course:
curl -s -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-d '{"name": "YOUR_NAME", "course": "TDS", "year": 2026}'What should you see?
httpbin echoes back your request. Look for the json field in the response:
{
"json": {
"name": "YOUR_NAME",
"course": "TDS",
"year": 2026
},
...
}This confirms the server received your JSON data correctly.
Exercise 3: Headers and authentication
# 1. Send a custom header:
curl -s https://httpbin.org/headers \
-H "X-Student-Name: Alice" \
-H "X-Course: TDS" | jq '.headers'
# 2. Test basic auth (username: testuser, password: testpass):
curl -s -u "testuser:testpass" https://httpbin.org/basic-auth/testuser/testpass
# 3. Test with WRONG password — what status code do you get?
curl -s -o /dev/null -w "%{http_code}\n" \
-u "testuser:wrongpass" https://httpbin.org/basic-auth/testuser/testpassAnswers
You’ll see your custom headers in the response:
{"X-Course": "TDS", "X-Student-Name": "Alice", ...}Successful auth returns:
{"authenticated": true, "user": "testuser"}Wrong password returns status code 401 (Unauthorized).
Exercise 4: Chain curl with jq
# Install jq if not present:
sudo apt install jq -y
# Fetch data and extract specific fields:
curl -s https://httpbin.org/get | jq '{ip: .origin, agent: .headers."User-Agent"}'Expected output
{
"ip": "your.ip.address",
"agent": "curl/8.x.x"
}jq extracted just the fields you asked for from the full response.
Exercise 5: MCQ
Q1: What does curl -s -o /dev/null -w "%{http_code}\n" URL output?
- A) The full response body
- B) The response headers
- C) Just the HTTP status code
- D) The URL itself
Answer
C — This clever combination:
-s= silent (no progress bar)-o /dev/null= discard the response body-w "%{http_code}\n"= print just the status code
Q2: Which flag makes curl show the full request AND response debug info?
- A)
-s - B)
-v - C)
-i - D)
-I
Answer
B — -v (verbose) shows the full request headers (lines starting with >) and response headers (lines starting with <), plus connection details.
Q3: You need to send {"action": "start"} as a POST request. Which curl command is correct?
- A)
curl -X GET url -d '{"action": "start"}' - B)
curl url -H "Content-Type: application/json" -d '{"action": "start"}' - C)
curl url -d "action=start" - D)
curl -X POST url -d {"action": "start"}
Answer
B — This sets the Content-Type to JSON and sends the JSON body. -d implies POST automatically. Option D is missing quotes around the JSON.