A guide to cURL

Table of Contents

A guide to cURL

Let's take this very slow. Take a deep breath.

Objective:

  • Second principle thinking for URL testing
  • Fun
  • More fun

Even though people don't understand, most of us already ran this command in their terminal when the endpoint is not reachable in browser:

curl google.com

If it was up, we would get something like:

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>

Another advanced command that helps us retrieve the status code instead of the http header.

curl -o /dev/null -s -w "%{http_code}" https://phind.com

phind.com was a AI search platform. Unfortunetely they couldn't continue. Therefore, striking the endpoint will return a 403 code.

What is cURL?

cURL stands for {client URL}.

curl serves as a command-line and scripting tool for data transfers, while its core library, libcurl, powers connectivity in diverse devices—from cars and TVs to routers, printers, audio gear, phones, tablets, medical equipment, set-top boxes, games, and media players—driving the internet transfer backbone for billions of software installations worldwide. curl

Practically every internet user on the planet relies on curl each day.

Who is this for?

  • Devs: To test endpoints, debug integrations, and understand HTTP.
  • Testers: For quick API health checks, load simulation, and automation.
  • Architects: To inspect traffic, verify security headers, and design robust systems.
  • Hobbyists

Chapter 1: Anatomy of cURL command

curl [options] [url]

You can identify various commands with: curl --help

The Basics

curl https://reflection.amals.xyz`

We discussed this before, it is a simple GET request.

curl -O https://reflection.amals.xyz/posts/media/CS/virtual-file-system.svg

It will download and save with the original filename. This can be any file.

curl -o myfile.html https://reflection.amals.xyz

-o can be used to save the response to a specific filename. Here, the html file is saved with content of my root html file.

Following Paths

curl -L https://google.com

We already seen the 3XX http headers. Without passing the --location|-L the curl will respond with the header file of the redirect. As we seen in the first example in the blog. By default cURL can go upto 50 redirects and get the information.

Activity: Run the commands with and without -L and grep the keyword like search.

Chapter 2: Speak HTTP

This section is almost helpful for developers and testers. Also for people who wanted to verify their API documentation.

Verbs/Methods

Until this point we have only used GET request. Let's do POST:

Calling syntax:

curl -X [method] [url]
curl -X POST https://api.example.com/users

Verbs: POST, PUT, DELETE

So you might have asked, what data are we passing?

We can add payload to the request.

Practical example:

curl -X POST -H "Content-Type: application/json" \
     -d '{"name":"Amal"}' https://api.example.com/users
  • -d is used to load the data.
  • -H is used for specifying the content type.

I don't have my endpoint to test the API for the given example. So the credit is for learning.

Modifying the Header

Adding Headers

We can use the same -H or --header to send custom HTTP headers like auth tokens:

curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/protected

Example:

curl -X POST https://api.groq.com/openai/v1/chat/completions \
  -H "Authorization: Bearer GROQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role": "user", "content": "Hello!"}],
    "model": "llama-3.1-8b-instant"
  }'

User-Agent Spoofing

-A or --user-agent overrides the default curl identifier:

curl -A "Mozilla/5.0 (compatible; MyBot/1.0)" https://example.com

Setting Referer

The -e or --referer option sets the HTTP "Referer" header, which tells the target server what page "referred" the request to that server. Like faking where the request came from.

curl -e "https://my-site.com" https://target.com

Why? Because websites often check the referer for security, analytics, or anti-bot protection. This makes target.com think we are clicked from my-site.com.

Real example:

curl -e "https://www.google.com/" https://example.com
# Check headers received
curl -I -e "https://facebook.com" https://x.com

Sending Data

We saw -d for JSON data. But we will discuss more:

Form Data (URL-encoded):

curl -d "username=amal&password=secret123" https://example.com/login

Binary Data:

When you need to send raw files or binary data, use --data-binary:

curl --data-binary @image.png -H "Content-Type: image/png" https://api.example.com/upload

The @ tells curl to read from a file. Without it, the literal text gets sent.

Multipart Forms (File Uploads):

This is how you upload files with forms:

curl -F "avatar=@/home/amal/photo.jpg" -F "bio=Hello" https://api.example.com/profile

The -F flag simulates a multipart form submission - perfect for profile pictures, document uploads, or anything that requires both files and text fields.

Chapter 3: The Inspector's Toolkit

We are taking an advance level here.

Verbose Mode (-v)

This is the most important flag. Ever. It shows everything - request headers, response headers, TLS handshake, the whole conversation:

curl -v https://example.com

You'll see something like:

* Trying 93.184.216.34:443...
* Connected to example.com (93.184.216.34) port 443 (#0)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.0.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html
< Content-Length: 1256
<
<!doctype html>
...

The > lines are what curl sent. The < lines are what came back. This is gold when your API isn't working properly.

Even Deeper: Trace

When -v isn't enough, go full detective with --trace:

curl --trace trace.txt https://example.com

This dumps every single byte to trace.txt. It's overwhelming, but sometimes you need to see exactly what's happening on the wire.

Or for ASCII-friendly output:

curl --trace-ascii trace.txt https://example.com

Silent Mode (-s)

Sometimes you don't want all that noise. Just the data:

curl -s https://api.example.com/data

The progress meter disappears. Useful for scripting.

Want to suppress errors but still see output? Combine with -S:

curl -sS https://example.com

Timing is Everything

This is where architects drool. The -w flag outputs timing information after the transfer:

curl -w "Time: %{time_total}s\n" -o /dev/null -s https://example.com

But here's the real magic - all the timing variables:

Variable What it measures
time_namelookup DNS resolution time
time_connect TCP handshake time
time_appconnect TLS/SSL handshake time
time_starttransfer Time to first byte (TTFB)
time_total Total request time

Real example - measuring API latency:

curl -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nFirst Byte: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
  -o /dev/null -s https://api.groq.com/v1/models

This tells you exactly where your latency is coming from. DNS slow? That's your network. TLS slow? Certificate issues? First byte slow? The server is thinking too hard.

Chapter 4: Handling Edge Cases

Real-world scenarios need more than basic requests. Also means, this will not be used most of the time.

Authentication

Basic Auth:

curl -u username:password https://example.com/secret

The -u flag handles the Base64 encoding for you. Clean and simple.

Bearer Tokens:

We already saw this, but here's a reminder:

curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/protected

Cookies

Cookies are just headers, but curl makes them easy.

Sending cookies:

curl -b "session_id=abc123" https://example.com/dashboard

Saving cookies:

curl -c cookies.txt https://example.com/login -d "user=amal"

Using saved cookies:

curl -b cookies.txt https://example.com/dashboard

This is how you test login flows - save the session cookie, then use it for subsequent requests.

Dealing with SSL

Sometimes you need to ignore certificate errors. Development, testing with self-signed certs:

curl -k https://self-signed.example.com

For more info, by defualt curl will use TLS/SSL certificate. Using -k skips that step.

Warning: Never use -k in production. Only for local development or testing.

Want to see certificate details?

curl -v https://example.com 2>&1 | grep -i certificate

Or get full certificate info:

curl --cert-status -v https://example.com

Chapter 5: cURL in the Wild

Let's see how this actually gets used.

Health Checks

The classic sysadmin one-liner:

curl -sf https://myapp.com/health && echo "App is up" || echo "App is down"

The flags: -s (silent), -f (fail on HTTP errors). If the health endpoint returns 200, it echoes "App is down" and exits with error.

Add this to cron for monitoring.

Testing Your Own API

You just wrote a new endpoint. Test it:

curl -X POST http://localhost:8080/api/v1/users \
  -H "Content-Type: application/json" \
  -d '{"name": "Amal", "email": "amal@example.com"}'

Or load the body from a file:

curl -X POST http://localhost:8080/api/v1/users \
  -H "Content-Type: application/json" \
  -d @user.json

That @file syntax is so useful.

Comparing HTTP Versions

Architects care about performance. Let's compare HTTP/1.1 vs HTTP/2:

# HTTP/2
curl --http2 -w "HTTP/2: %{time_total}s\n" -o /dev/null -s https://example.com

# HTTP/1.1
curl --http1.1 -w "HTTP/1.1: %{time_total}s\n" -o /dev/null -s https://example.com

Run these a few times and you'll see the difference. (HTTP/2 usually wins for multiple requests due to multiplexing).

Downloading Files

Download with progress bar:

curl -O https://example.com/big-file.zip

Resume a failed download:

curl -C - -O https://example.com/big-file.zip

The -C - tells curl to continue from where it left off.

Chapter 6: cURL vs The World

cURL vs Postman

Postman is great for building and organizing requests. It's a GUI. You can actually import curl commands into Postman:

Import -> Paste Raw Text -> Paste your curl command

cURL is the raw, scriptable form. It's universal. Every language can execute a shell command. Paste a curl into Python, Node, Go, it just works.

==Use Postman for complex workflows. Use curl for quick tests and automation.==

cURL vs Wget

Feature cURL Wget
Protocols HTTP, HTTPS, FTP, SFTP, and many more FTP, HTTP, HTTPS
Recursive downloads No (single files) Yes (mirroring)
POST data Yes Yes, but limited
Library (libcurl) Yes No

Wget is for wget -r https://example.com - recursively downloading entire websites.

cURL is for precise, single-endpoint interactions.

They complement each other.

Conclusion

The terminal doesn't lie. What you see is what you get.

Cheat Sheet

Category Flag Description Example
Core -X HTTP Method -X POST
Data -d Send data -d "key=val"
Data -F Form upload -F "file=@img.jpg"
Headers -H Custom Header -H "Content-Type: application/json"
Auth -u Basic Auth -u user:pass
Debug -v Verbose output -v https://site.com
Debug -w Write-out timing -w "%{time_total}"
Output -o Save to file -o index.html
Output -O Save with original name -O
Follow -L Follow redirects -L
Cookies -b Send cookies -b "session=x"
Cookies -c Save cookies -c cookies.txt
Insecure -k Skip SSL check -k
Silent -s Silent mode -s

What's Next?

Pick one flag from this list you haven't used. Open your terminal. Try it.

That's how you learn.

← How Humans count (Decimal System) Foundations of Linear Algebra: Vectors and the Field Axioms →