How do you talk to a server without opening a browser?
Every time you load a webpage, your browser sends a request to a server and gets a response. But what if you want to test an API? Debug a backend issue? Automate a task?
You need a way to send those requests directly. That's where cURL comes in.
What you'll learn:
- What a server is and why we communicate with it
- What cURL is and why programmers use it
- How to make your first request
- How to fetch and send data with APIs
- Common mistakes and how to avoid them
Part 1: What is a Server? (Quick Context)
Before we dive into cURL, let's establish one concept.
The Client-Server Model
When you visit a website:
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLIENT-SERVER MODEL │
└─────────────────────────────────────────────────────────────────────────────┘
You (Client) Server
┌────────────────┐ ┌────────────────┐
│ │ "Give me google.com" │ │
│ Browser │ ────────────────────────────►│ Web Server │
│ │ │ (Google) │
│ │ "Here's the webpage" │ │
│ │ ◄────────────────────────────│ │
└────────────────┘ └────────────────┘
REQUEST → → RESPONSE
Client = The thing making the request (browser, app, your code)
Server = The thing responding with data
Why Talk to Servers?
| As a Developer, You Might Need To... | Example |
|---|---|
| Test your API before building a frontend | "Does my /users endpoint work?" |
| Debug why a request is failing | "What status code is it returning?" |
| Automate tasks | "Download this file every hour" |
| Explore third-party APIs | "What does the GitHub API return?" |
Browsers are great, but they add layers. Sometimes you need to talk to a server directly.
Part 2: What is cURL?
The Definition
cURL stands for "Client URL" — a command-line tool to transfer data to or from a server.
Think of it as a text-based browser. Instead of clicking buttons and seeing rendered pages, you type commands and see raw responses.
Why Not Just Use a Browser?
┌─────────────────────────────────────────────────────────────────────────────┐
│ BROWSER vs cURL │
└─────────────────────────────────────────────────────────────────────────────┘
BROWSER cURL
┌────────────────────────┐ ┌────────────────────────┐
│ • Renders HTML/CSS │ │ • Shows raw response │
│ • Runs JavaScript │ │ • No rendering │
│ • Handles cookies │ │ • Full control │
│ • Visual interface │ │ • Scriptable │
│ • Hard to automate │ │ • Easy to automate │
└────────────────────────┘ └────────────────────────┘
Good for: Browsing Good for: Testing, debugging,
as a user automation, APIs
Why Programmers Love cURL
| Reason | Explanation |
|---|---|
| It's everywhere | Pre-installed on Mac, Linux, Windows 10+ |
| It's scriptable | Put cURL in shell scripts for automation |
| It shows the truth | No rendering tricks—you see exactly what the server sends |
| It's fast | No browser overhead |
| It's precise | Full control over headers, method, body |
Part 3: Your First cURL Command
Let's make your first request. Open your terminal.
The Simplest Command
curl https://example.com
What You'll See
<!doctype html>
<html>
<head>
<title>Example Domain</title>
...
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents.</p>
...
</div>
</body>
</html>
What Just Happened?
┌─────────────────────────────────────────────────────────────────────────────┐
│ YOUR FIRST cURL REQUEST │
└─────────────────────────────────────────────────────────────────────────────┘
Your Terminal Server
┌────────────────┐ ┌────────────────┐
│ │ GET https://example.com │ │
│ curl command │ ────────────────────────────►│ example.com │
│ │ │ │
│ │ 200 OK + HTML content │ │
│ │ ◄────────────────────────────│ │
└────────────────┘ └────────────────┘
1. You typed the command
2. cURL sent an HTTP GET request
3. The server responded with HTML
4. cURL printed the response to your terminal
Congratulations! You just made an HTTP request without a browser.
Part 4: Understanding the Response
That HTML blob was the response body. But there's more to a response than just the body.
The Full HTTP Response
An HTTP response has three parts:
┌─────────────────────────────────────────────────────────────────────────────┐
│ HTTP RESPONSE STRUCTURE │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ STATUS LINE │
│ HTTP/1.1 200 OK │ ← Status code
├─────────────────────────────────────────────────────┤
│ HEADERS │
│ Content-Type: text/html │ ← Metadata
│ Content-Length: 1256 │
│ Date: Mon, 31 Jan 2026 17:30:00 GMT │
├─────────────────────────────────────────────────────┤
│ BODY │
│ <!doctype html> │ ← The actual
│ <html> │ content
│ ... │
└─────────────────────────────────────────────────────┘
Seeing Headers with -i
By default, cURL only shows the body. To see headers too:
curl -i https://example.com
Output:
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1256
Date: Mon, 31 Jan 2026 17:30:00 GMT
...
<!doctype html>
<html>
...
Understanding Status Codes
| Code | Meaning | What It Means for You |
|---|---|---|
| 200 | OK | Request succeeded |
| 201 | Created | Resource created (after POST) |
| 301/302 | Redirect | Resource moved elsewhere |
| 400 | Bad Request | You sent invalid data |
| 401 | Unauthorized | Need to log in |
| 403 | Forbidden | Logged in but not allowed |
| 404 | Not Found | Resource doesn't exist |
| 500 | Internal Server Error | Server broke |
Only Headers (No Body)
Sometimes you just want to check if a URL is alive:
curl -I https://example.com
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1256
-I (capital I) = HEAD request, returns only headers.
Part 5: GET Requests — Fetching Data
What is GET?
GET = "Give me data"
It's the most common HTTP method. Every time you open a webpage, your browser sends a GET request.
cURL uses GET by default, so:
curl https://example.com
# Same as:
curl -X GET https://example.com
Working with APIs
APIs return JSON instead of HTML. Let's try a public API:
curl https://jsonplaceholder.typicode.com/users/1
Response:
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"city": "Gwenborough"
}
...
}
Making Output Cleaner
Silent mode (hide progress bar):
curl -s https://jsonplaceholder.typicode.com/users/1
Pipe to jq (format JSON beautifully):
curl -s https://jsonplaceholder.typicode.com/users/1 | jq
[!TIP]
jqis a JSON processor. Install it withbrew install jq(Mac) orapt install jq(Linux) orchoco install jq(Windows).
Query Parameters
Many APIs accept parameters in the URL:
curl "https://api.github.com/search/repositories?q=javascript&sort=stars"
[!NOTE]
Use quotes around URLs with special characters like?,&,=.
Part 6: POST Requests — Sending Data
What is POST?
POST = "Take this data and do something with it"
Use POST when you want to:
- Create a new resource
- Submit a form
- Send data to be processed
The Basic POST Command
curl -X POST https://jsonplaceholder.typicode.com/posts
But this sends an empty request. We need to add data.
Sending JSON Data
curl -X POST https://jsonplaceholder.typicode.com/posts \
-H "Content-Type: application/json" \
-d '{"title": "My Post", "body": "Hello World", "userId": 1}'
Let's break this down:
| Flag | Meaning |
|---|---|
-X POST |
Use POST method |
-H "Content-Type: application/json" |
Tell server we're sending JSON |
-d '{...}' |
The data to send |
Response:
{
"title": "My Post",
"body": "Hello World",
"userId": 1,
"id": 101
}
The server created a resource and returned it with a new id!
Diagram: HTTP Request Structure
┌─────────────────────────────────────────────────────────────────────────────┐
│ HTTP REQUEST STRUCTURE │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ REQUEST LINE │
│ POST /posts HTTP/1.1 │ ← Method + Path
├─────────────────────────────────────────────────────┤
│ HEADERS │
│ Host: jsonplaceholder.typicode.com │
│ Content-Type: application/json │ ← What we're sending
│ Content-Length: 52 │
├─────────────────────────────────────────────────────┤
│ BODY │
│ {"title": "My Post", "body": "Hello World"} │ ← The data
└─────────────────────────────────────────────────────┘
Form Data (Alternative)
Some APIs expect form data instead of JSON:
curl -X POST https://httpbin.org/post \
-d "username=john&password=secret"
This sends application/x-www-form-urlencoded data (like an HTML form).
Part 7: Talking to Real APIs
Let's practice with real, public APIs.
Example 1: Get Weather Data
# Free weather API (no key needed)
curl -s "https://wttr.in/London?format=3"
Output:
London: ☀️ +15°C
Example 2: GitHub User Info
curl -s https://api.github.com/users/torvalds | jq
Output (truncated):
{
"login": "torvalds",
"name": "Linus Torvalds",
"company": "Linux Foundation",
"followers": 200000,
"public_repos": 7
}
Example 3: GitHub API with Authentication
Some APIs require authentication:
curl -H "Authorization: token YOUR_GITHUB_TOKEN" \
https://api.github.com/user
Or using Basic Auth:
curl -u username:password https://api.example.com/protected
Where cURL Fits in Development
┌─────────────────────────────────────────────────────────────────────────────┐
│ WHERE cURL FITS IN BACKEND DEVELOPMENT │
└─────────────────────────────────────────────────────────────────────────────┘
Development Workflow:
1. Build API endpoint
│
▼
2. Test with cURL ◄─── You are here!
│
▼
3. Write frontend code
│
▼
4. Write automated tests
│
▼
5. Deploy
cURL is your quick testing tool before writing real code!
Part 8: Common Beginner Mistakes
Mistake 1: Forgetting the Protocol
# ❌ Wrong
curl example.com
# ✅ Correct
curl https://example.com
Why? cURL needs to know whether to use HTTP or HTTPS.
Mistake 2: Missing Content-Type Header
# ❌ Server might not understand your JSON
curl -X POST https://api.example.com/data -d '{"name":"John"}'
# ✅ Tell the server you're sending JSON
curl -X POST https://api.example.com/data \
-H "Content-Type: application/json" \
-d '{"name":"John"}'
Why? Without Content-Type, the server might parse your data incorrectly.
Mistake 3: Quote Issues on Windows
# ❌ Won't work on Windows CMD
curl -d '{"name":"John"}' https://api.example.com
# ✅ Use double quotes and escape inner quotes on Windows
curl -d "{\"name\":\"John\"}" https://api.example.com
Why? Windows CMD doesn't handle single quotes the same way.
Mistake 4: Not Reading Error Messages
$ curl https://api.example.com/protected
{"error": "Unauthorized", "message": "Missing authentication token"}
Read the response! It often tells you exactly what's wrong.
Mistake 5: SSL Certificate Errors
# If you see "SSL certificate problem"
# ❌ Don't blindly skip verification in production
curl -k https://example.com
# ✅ Fix the certificate issue or understand why it's happening
Why? -k bypasses security. Use it only for local development.
Mistake 6: Redirects Not Followed
# If a URL redirects, you'll see a 301/302
curl http://github.com
# Returns redirect response
# Follow redirects with -L
curl -L http://github.com
# Returns actual page
Part 9: Quick Reference
Essential Flags
| Flag | Purpose | Example |
|---|---|---|
-X |
HTTP method | -X POST |
-H |
Add header | -H "Content-Type: application/json" |
-d |
Send data | -d '{"key":"value"}' |
-i |
Show response headers | -i |
-I |
Only headers (HEAD request) | -I |
-s |
Silent (no progress bar) | -s |
-o |
Save output to file | -o response.json |
-L |
Follow redirects | -L |
-u |
Basic auth | -u user:pass |
-v |
Verbose (debug mode) | -v |
Common Patterns
GET request:
curl https://api.example.com/users
GET with headers:
curl -H "Authorization: Bearer TOKEN" https://api.example.com/users
POST JSON:
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "John", "email": "john@example.com"}'
PUT (update):
curl -X PUT https://api.example.com/users/1 \
-H "Content-Type: application/json" \
-d '{"name": "Jane"}'
DELETE:
curl -X DELETE https://api.example.com/users/1
Download file:
curl -o image.jpg https://example.com/photo.jpg
Part 10: Next Steps
You now know enough cURL to:
- ✅ Test any REST API
- ✅ Debug backend endpoints
- ✅ Understand HTTP requests and responses
- ✅ Automate simple tasks
Practice APIs
| API | URL | What You Can Do |
|---|---|---|
| JSONPlaceholder | jsonplaceholder.typicode.com | Fake REST API for testing |
| httpbin | httpbin.org | Echo service—see what you sent |
| GitHub | api.github.com | Real data, public endpoints |
| wttr.in | wttr.in | Weather in your terminal |
Keep Learning
-
Explore more flags:
curl --helporman curl - Try Postman or Insomnia: GUI alternatives to cURL
- Learn about API authentication: OAuth, API keys, JWT
- Automate with scripts: Combine cURL with bash scripts
Conclusion
cURL is your direct line to any server.
| What You Learned | Key Takeaway |
|---|---|
| What servers are | Client sends request → Server sends response |
| What cURL is | Command-line tool for HTTP requests |
| GET requests | Fetch data with curl URL
|
| POST requests | Send data with -X POST -d
|
| Headers | Use -H for Content-Type, Auth, etc. |
| Debugging | Use -i to see headers, -v for verbose |
Every API you'll ever use speaks HTTP. Now you can speak it too.
Go test your APIs. Happy curling! 🚀
Top comments (0)