Testing with curl: idempotency, pagination and rate limits
Send and inspect requests from the command line, prove which methods are idempotent, and test paging, limits and 429 handling.
Not every environment has Postman, and interviewers like to see that you can test an API from a terminal. curl also makes three advanced topics concrete: idempotency, pagination and rate limiting. Each has a small set of tests you should be able to list from memory.
curl essentials
curl -i https://api.example.com/orders/1042 -H "Authorization: Bearer $TOKEN"
curl -i -X POST https://api.example.com/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"sku":"A-100","qty":2}'
curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" https://api.example.com/health
-i prints response headers with the body, -X sets the method, -H adds a header, -d sends a body. The third form prints only the status and time. Add -v to see the exact request that went out, including the headers you thought you set.
Idempotency
A request is idempotent when sending it once or five times leaves the server in the same state. GET, PUT and DELETE should be idempotent; POST usually is not. Test it by sending the same request twice and comparing the state. Worked example: send PUT /users/7 with the same body twice; the second call must return success and the record must be unchanged. Send DELETE /users/7 twice; the second call may return 404 or 204, but it must not delete someone else. Send POST /orders twice and two orders should exist, unless the API supports an Idempotency-Key header; then repeat the POST with the same key and check only one order was created.
Pagination and rate limits
For a list endpoint such as GET /orders?page=2&limit=20, test: the first page returns the stated limit; the last page returns the remainder; a page past the end returns an empty list, not an error; limit=0 and limit=1000 are rejected or capped as documented; sort order is stable so items do not repeat across pages. Create 45 records, request pages of 20, and expect 20, 20, 5, then 0.
For rate limits, read the headers on a normal response (often X-RateLimit-Remaining), then exceed the limit in a loop:
for i in $(seq 1 120); do curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/health -H "Authorization: Bearer $TOKEN"; done | sort | uniq -c
Expect 200s followed by 429s, a Retry-After header on the 429, and a return to 200 after that delay. The limit should apply per key, not block everyone.
Common mistakes and a practice habit
- Forgetting
Content-Type: application/json, so the server reads the body as a form and rejects it. - Testing idempotency only by status code and not by checking the stored data afterwards.
- Skipping the page-past-the-end case.
- Running the rate-limit loop against production.
Practice habit. Keep a curl.md file with one working example per method against a practice API. Each week add one idempotency, one pagination and one rate-limit check, with the observed result.
More in Software testing