You can actually make curl do way more than just download files; it’s your go-to for interacting with web services directly from the command line.
Let’s see it in action. Imagine we want to get some data from a public API, like a list of public holidays. Here’s how you’d fetch that data from the date.nager.at API for the US:
curl "https://date.nager.at/api/v3/PublicHolidays/US/2024"
This command hits the specified URL and dumps the JSON response right to your terminal. But that’s just the start. You can send data too. For instance, if you wanted to POST some JSON to a test endpoint:
curl -X POST -H "Content-Type: application/json" -d '{"name": "Bender", "type": "Robot"}' http://httpbin.org/post
Here, -X POST explicitly sets the HTTP method, -H "Content-Type: application/json" tells the server what kind of data we’re sending, and -d '{"name": "Bender", "type": "Robot"}' provides the actual data payload. httpbin.org is a fantastic playground for testing HTTP requests.
The real power comes from understanding how curl maps to HTTP concepts. The URL is the endpoint. The method (GET, POST, PUT, DELETE, etc.) determines the action. Headers (-H) provide metadata about the request or the client. The body (-d or --data) carries the actual payload for methods like POST or PUT.
Beyond basic requests, you can manage authentication. For basic HTTP authentication:
curl -u "username:password" https://api.example.com/resource
For more complex authentication, like sending an API key in a header:
curl -H "Authorization: Bearer YOUR_API_KEY" https://api.example.com/resource
You can also inspect the full HTTP response, including headers, with -i:
curl -i "https://date.nager.at/api/v3/PublicHolidays/US/2024"
This will show you the status code, response headers, and then the body. This is crucial for debugging, as you can see exactly what the server is sending back.
curl also handles redirects automatically by default. If you need to explicitly follow them or not, use -L to follow or -f to fail silently on server errors without outputting the body (though it will still return a non-zero exit code).
When you’re dealing with more complex data structures or need to send files, the -d flag can take a file path prefixed with @, like -d @mydata.json. This reads the content of mydata.json and sends it as the request body.
The most commonly misunderstood aspect of curl is how it handles different types of data payloads. While -d is common for form-encoded data, for JSON, you almost always need to couple it with the Content-Type: application/json header. If you just use -d '{"key": "value"}' without the header, many APIs will treat it as application/x-www-form-urlencoded and reject it or misinterpret it.
You can save the output to a file using standard shell redirection:
curl "https://date.nager.at/api/v3/PublicHolidays/US/2024" > holidays.json
This redirects the standard output of the curl command into the holidays.json file.
The next step is often integrating curl into scripts, where you’ll want to parse the JSON output, perhaps using tools like jq.