HTTP Clients: curl and HTTPie for API Development
In this tutorial, you'll learn curl and HTTPie for API testing and development including headers, authentication, request bodies, file uploads, and scripting API calls for automation.
Why HTTP Clients Matter
APIs power modern applications. Testing API endpoints during development should be fast and repeatable. Graphical tools like Postman are useful, but command-line HTTP clients give you scriptable, reproducible, and composable API interactions that can be integrated directly into your development workflow and CI pipeline.
By the end of this guide, you will use curl and HTTPie to make all common HTTP requests, handle authentication, upload files, and script API tests.
curl: The Universal HTTP Client
curl is the most widely used command-line HTTP client. It is installed on virtually every Unix system and supports dozens of protocols.
flowchart LR A[curl Command] --> B[URL] A --> C[Method] A --> D[Headers] A --> E[Data] A --> F[Authentication] B --> G[HTTP Request] G --> H[HTTP Response] H --> I[Status Code] H --> J[Headers] H --> K[Body]
Basic GET Requests
# Simple GET
curl https://api.example.com/users
# GET with verbose output
curl -v https://api.example.com/users
# GET with response headers
curl -i https://api.example.com/users
# GET with custom header
curl -H "Accept: application/json" https://api.example.com/users
Expected Output
$ curl -i https://jsonplaceholder.typicode.com/todos/1
HTTP/2 200
content-type: application/json; charset=utf-8
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
POST Requests
# POST with JSON body
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name":"Alice","email":"alice@example.com"}'
# POST with form data
curl -X POST https://api.example.com/users \
-d "name=Alice" \
-d "email=alice@example.com"
# POST with file content as body
curl -X POST https://api.example.com/data \
-d @data.json
Authentication
# Basic auth
curl -u username:password https://api.example.com/protected
# Bearer token
curl -H "Authorization: Bearer token123" https://api.example.com/protected
# API key in header
curl -H "X-API-Key: abc123" https://api.example.com/protected
# API key in query parameter
curl "https://api.example.com/protected?api_key=abc123"
File Uploads
# Single file upload
curl -F "file=@photo.jpg" https://api.example.com/upload
# Multiple fields
curl -F "file=@document.pdf" \
-F "description=Annual report" \
https://api.example.com/upload
# Upload with content type
curl -F "file=@image.png;type=image/png" https://api.example.com/upload
Downloading Files
# Download file with original name
curl -O https://example.com/file.zip
# Download with custom name
curl -o output.zip https://example.com/file.zip
# Resume interrupted download
curl -C - -O https://example.com/large-file.zip
Advanced curl
# Follow redirects
curl -L https://example.com/redirect
# Timeout after 30 seconds
curl --connect-timeout 30 --max-time 60 https://api.example.com
# Skip SSL verification (insecure, use only for testing)
curl -k https://internal-server.example.com
# Send multiple headers
curl -H "Accept: application/json" \
-H "Authorization: Bearer token" \
-H "X-Request-ID: abc-123" \
https://api.example.com/data
# Cookie handling
curl -c cookies.txt https://api.example.com/login
curl -b cookies.txt https://api.example.com/profile
Scripting with curl
#!/bin/bash
# api-test.sh
API_BASE="https://api.example.com"
# Login
TOKEN=$(curl -s -X POST "$API_BASE/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"secret"}' \
| jq -r '.token')
# Create resource
CREATE_RESPONSE=$(curl -s -X POST "$API_BASE/items" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Test Item","price":9.99}')
echo "Created: $CREATE_RESPONSE"
# Get resource by ID
ITEM_ID=$(echo "$CREATE_RESPONSE" | jq -r '.id')
GET_RESPONSE=$(curl -s "$API_BASE/items/$ITEM_ID" \
-H "Authorization: Bearer $TOKEN")
echo "Retrieved: $GET_RESPONSE"
HTTPie: Human-Friendly HTTP Client
HTTPie is designed for API testing with an intuitive command syntax and colorized output.
Installation
# macOS
brew install httpie
# Linux
sudo apt install httpie -y
Basic Usage
# Simple GET
http https://api.example.com/users
# GET with verbose output
http -v https://api.example.com/users
# GET with query parameters
http "https://api.example.com/users?role=admin&limit=10"
# Or:
http https://api.example.com/users role==admin limit==10
Expected Output
$ http https://jsonplaceholder.typicode.com/posts/1
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit..."
}
POST Requests
# POST with JSON body (automatic)
http POST https://api.example.com/users \
name=Alice \
email=alice@example.com \
role:=admin
# The := indicates a JSON number/boolean, = for string
http POST https://api.example.com/items \
name="Test Item" \
price:=9.99 \
inStock:=true
Authentication
# Basic auth
http -a username:password https://api.example.com/protected
# Bearer token
http https://api.example.com/protected \
"Authorization: Bearer token123"
# Using the auth header shorthand
http https://api.example.com/protected \
"Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
File Uploads
# Upload a file
http -f POST https://api.example.com/upload \
file@~/photo.jpg
# Multiple fields with upload
http -f POST https://api.example.com/upload \
file@~/document.pdf \
description="Annual Report"
Sessions
# Start a session
http --session=mysession POST https://api.example.com/login \
username=admin \
password=secret
# Reuse session
http --session=mysession GET https://api.example.com/profile
Redirects and Output
# Follow redirects
http --follow https://example.com/redirect
# Download file
http --download https://example.com/file.zip
# Output body only
http --body https://api.example.com/data
# Output headers only
http --headers https://api.example.com/data
Comparison Table
| Feature | curl | HTTPie |
|---|---|---|
| Syntax | Verbose, flags | Intuitive, short |
| Output | Raw | Colorized, formatted |
| JSON handling | Manual (-H + -d) |
Automatic |
| Sessions | Cookie file (-b, -c) |
Built-in (--session) |
| File uploads | -F flag |
-f flag with @ |
| Installation | Pre-installed on most systems | Requires install |
| Scripting | Excellent (bash-friendly) | Good |
| Color output | No (use -w for customization) |
Yes (default) |
Common Errors
| Problem | Cause | Fix |
|---|---|---|
curl: (60) SSL certificate problem |
Self-signed or invalid cert | Use -k for testing or add the CA cert |
curl: (22) The requested URL returned error: 404 |
Wrong URL | Check the endpoint path and base URL |
HTTPie: JSONDecodeError when sending string |
Missing := for non-string values |
Use := for numbers/booleans, = for strings |
Connection refused |
Server not running | Start the server |
401 Unauthorized |
Missing or invalid auth | Check your authentication method and credentials |
Practice Questions
1. How do you send a POST request with JSON body using curl?
curl -X POST https://api.example.com/data -H "Content-Type: application/json" -d '{"key":"value"}'.
2. What is the difference between = and := in HTTPie request data?
= sends a string value. := sends a JSON value (number, boolean, object, array).
3. How do you download a file with curl while preserving the filename?
curl -O https://example.com/file.zip.
4. How do you set a timeout for a curl request?
--connect-timeout 30 --max-time 60.
5. What does the --session flag do in HTTPie?
It persists cookies and headers across multiple requests, simplifying multi-step API flows.
Challenge
Write a bash script that uses curl to perform a complete CRUD workflow against a REST API: create a resource, read it by ID, update it, list all resources, and delete it. Include error handling with status code checks and proper authentication.
Real-World Task
Use HTTPie to test a GitHub API endpoint. Start with the GET /users/{username} endpoint, then explore authenticated endpoints using a personal access token. Use the --session feature to persist authentication across multiple requests. Create a script that retrieves your repositories, issues, and pull requests.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro