Skip to content

HTTP Clients: curl and HTTPie for API Development

DodaTech Updated 2026-06-22 6 min read

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.

Should I use curl or HTTPie?

Use HTTPie for interactive API testing and development. Its readable syntax and colorized output make debugging easier. Use curl for scripting and automation because it is available everywhere.

Can curl handle API pagination?

No, pagination requires scripting. You typically follow Link headers (for REST APIs) or page through results in a loop.

How do I debug HTTPS issues with curl?

Use -v for verbose output, which shows the TLS handshake and certificate chain. Use --trace for even more detail.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro