Replacing curl with HTTPie

Elliot Forbes Elliot Forbes ⏰ 4 Minutes 📅 Sep 1, 2024

If you are building out http-based services, it’s almost inevitable that you’ll need to craft HTTP requests in order to validate some of your endpoints.

Recently, I’ve become a bit of a convert away from traditional curl commands and started to adopt the tool HTTPie, which is potentially pronounced as HTT-pie?

It’s been a fantastic little tool that allows me to craft more natural HTTP requests quickly and easily and also lets me drop back down to raw curl should I need it.

This article is mostly intended to highlight how simple general tasks are with the tool and also act as a cheat-sheet for myself that has been distilled down to something that’s easier to grok.

Installation

Installation is incredibly straightforward:

# For MacOS 
$ brew install httpie

# For Windows
$ choco install httpie

Full and up-to-date installation instructions can be found here - https://httpie.io/docs/cli/installation

Sending Requests

Now that we’ve got this installed, let’s dive in and see how we can use it to craft requests:

# note: GET is optional here
$ http GET https://my-api.com/v1/health
HTTP/1.1 200 OK
content-encoding: gzip
content-type: application/json; charset=utf-8
date: Sun, 01 Sep 2024 06:38:19 GMT
fly-request-id: 01J6P4WKZCEN8F7V5FZSQ20JN5-ewr
server: Fly/e42c399f (2024-08-28)
transfer-encoding: chunked
via: 1.1 fly.io

{
    "message": "hello world!"
}

Fairly straightforward, and you may be asking “what advantage does this have over curl?”. Well, if you’ve been in the industry for a while, you’re likely not going to see much benefit. You’ll probably find it’s not worthwhile shifting over to this new tool for all your worldly HTTP needs.

But you do have to admit, this feels far more intuitive to write requests like this.

Setting the HTTP Verb

So in the above example, we’ve explicitly used the GET request. Sending other types of request is as simple as swapping out this verb which is really quite nice.

# sending a delete request
$ http DELETE https://my-api.com/v1/resource

# sending a POST request
$ http POST https://my-api.com/v1/resource

# sending a PUT request
$ http PUT https://my-api.com/v1/resource

Sending Payloads

Setting the payloads for these requests is also really quite straightforward. You can set key/value pairs like so:

$ http POST https://my-api.com/v1/resource some-key=some-value
# This would then send a payload of:
# {
#     "some-key": "some-value"
# } 

Typically payloads tend to be a little more nested than the example above, but thankfully this task is also just as straightforward using a syntax that looks a little like this: top-level-key[nested-key]

$ http POST https://my-api.com/v1/resource some-key[nested-key]=some-value
# This would then send a payload of:
# {
#     "some-key": {
#         "nested-key": "some-value"
#     }
# } 

Authentication

Ok, so in an ideal world, we would be able to access these valuable endpoints above without having to worry ourselves about authentication. But we live in the real-world and everything and anything you put into a live environment should have some form of authentication (and authorization) associated with it.

Again, HTTPie makes the job of sending authentication credentials fairly straightforward:

# Basic Auth
$ http -a username:password POST https://my-api.com/v1/resource some-key[nested-key]=some-value

# The more standard auth token approach
$ http -A bearer -a token POST https://my-api.com/v1/resource some-key[nested-key]=some-value

Additional Headers

So the final thing I’d like to cover in this quick-start guide is how you send HTTP headers alongside your request.

We define these much the same way that we do for payload values, but the one difference is the use of : to indicate that it’s a header value you are setting. For example, appending Content-Type: application/json would set this header for us:

# setting the `Content-Type` header
$ http POST https://my-api.com/v1/resource Content-Type:application-json some-key[nested-key]=some-value 

# setting an arbitrary header
$ http GET https://my-api.com/v1/resource My-Awesome-Header:super-awesome

Running the above with -v or the --verbose flag appended to the request then allows us to validate these headers are being appropriatey set:

$ http GET https://tutorialedge-service.fly.dev/api/health My-Awesome-Header:super-awesome -v
GET /api/health HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: tutorialedge-service.fly.dev
My-Awesome-Header: super-awesome
User-Agent: HTTPie/3.2.3

# the response body below...

Conclusion

Hopefully you found this interesting and are now pondering the switch from curl to HTTPie! So far it has been fantastic for me and made things just that little bit more enjoyable if you’d believe that!

Let me know your thoughts in the comments section down below!