Love letter to Hurl

Table of contents

Hurl is a command-line interface tool (CLI) that makes testing and automating HTTP APIs easy and enjoyable.

Yeap, “testing”, “easy”, and “enjoyable”, in the same sentence. Not common.👌

I realized that I have been posting a lot about the managed platform I am building to run Hurl scripts for you (Skybear.NET), without writing about the underlying star of the show.

This article elaborates on why I use and love Hurl for most of my end-to-end testing and HTTP automation needs. From testing Go server APIs, to JavaScript APIs on Cloudflare Workers, to simply chaining a few API calls together to integrate different services into a pipeline.

Hurl

Hurl is a command line tool that runs HTTP requests defined in a simple plain text format.

It can chain requests, capture values and evaluate queries on headers and body response. Hurl is very versatile: it can be used for both fetching data and testing HTTP sessions.

Hurl makes it easy to work with HTML content, REST / SOAP / GraphQL APIs, or any other XML / JSON based APIs.

— By hurl.dev

The hurl.dev website is really, really good. Detailed documentation with plenty examples and snippets of how to do anything you want with Hurl (see Samples docs).

The above quote is how they introduce Hurl. Notice that they don’t focus on “just testing”.

Hurl’s power is that it’s an HTTP request automation tool. Testing is just one use-case of it.

The fact that you can chain requests, extract data from responses and pass them down to subsequent requests, and target any API content type makes it an amazing Swiss-army knife tool for anything that speaks HTTP.

It’s curl wrapped in a nice package! ❤️

Love letter

I have been writing code for more than 15 years at this point. Professionally (getting paid for it) for more than a decade.

I tried a lot of testing frameworks and tools, some with success, some with frustration, and some that were rejected on first sight. There are hundreds if not thousands of testing tools, from language-specific frameworks, to generic tools, to in-house hand-written tests with code.

I first found out about Hurl 2 years ago, when it was still at version 4.0.0 (see all releases).

Hurl was a love at first sight kind of thing.😍 Not only that, but each of the releases since, make it even more awesome.

GET https://www.skybear.net/_live-demo/secure.json
Authentication: Bearer sample-token-123
HTTP 200
{"ok":true}

Look at the above snippet. Zero unnecessary overhead or boilerplate.

I would bet that you already understand what it does just by looking at it, but let’s go through it.

Line 1 sends a GET request. Line 2 configures the Authentication header of the request.

Line 3 asserts that we get back a 200 response status code. Line 4 asserts the full response body content.

There is nothing to remove to make it simpler. That’s freakin awesome!

There is a more flexible and more powerful [Asserts] block with special helpers to do assertions. For example, the above snippet is equivalent to the following:

GET https://www.skybear.net/_live-demo/secure.json
Authentication: Bearer sample-token-123
HTTP 200

[Asserts]
body == "{\"ok\":true}"
# or
jsonpath "$.ok" == true

Are you not interested in assertions, and just want to fire off some requests? Have at it:

GET https://www.skybear.net/_live-demo/secure.json
Authentication: Bearer sample-token-123

Do you want to repeat a request 5 times with 100ms space between them?

GET https://www.skybear.net/_live-demo/get.json
[Options]
repeat: 5
delay: 100ms

Run the above examples for free with the Skybear.NET Open Editor.

Hurl has a plethora of assertions you can do (see Asserting Response docs).

It also has cool variable capturing from responses (see Capturing Response docs) which is useful for extracting data from a response body or header and reusing it later either in assertions or subsequent requests. This is very useful for example when you are creating a new resource by issuing a POST request and extracting the created resource’s ID from the response in order to query other endpoints for that identifier next.

Specifying the body for the request is as simple as the URL and headers too. You can send JSON, XML, GraphQL, just a multiline string, multipart form-data, and everything else you need (see Request docs).

Another feature I love for easy testing is that you can use injected variables in your scripts (see Injecting Variables docs).

Imagine for example that your API has a staging deployment at staging.example.com and the production deployment at www.example.com. You can adapt your actual Hurl file to use https://{{subdomain}}.example.com and inject the subdomain variable when you run the CLI.

Variables can be injected as CLI arguments (--variable subdomain=staging), as environment variables (HURL_subdomain=staging hurl <rest cli arguments>), or put all of them in a staging.env file and pass the file as command line argument (--variables-file staging.env).

Personally, I usually start off with the CLI arguments, and then once the scripts are fully fleshed out move them to .env files.

Hurl also comes with other goodies.🥳

Running all the *.hurl files in a directory tree in parallel makes up for a super fast testing experience, limited only by the target API’s latency! It’s written in Rust after all, and taking full advantage of it.

My favourite goody feature is the --report-json option (introduced in 5.0.0 - see announcement) which creates a detailed JSON report of every request made by Hurl, while also dumping every single response body received and referencing it in the report. This is a great way to debug my APIs actually end-to-end, with full introspection to headers, duration timings, and full response bodies!🚀

I only covered the tip of the iceberg. It’s so good!

Conclusion

If you are doing anything with HTTP-based APIs and websites, do yourself a favour and integrate Hurl into your daily workflow.

Make your HTTP tasks easier, simpler, and more enjoyable.

I use Hurl in my personal projects for quick and easy end-to-end tests without wasting time with unit tests and code refactoring during feature development (see Tiddlyflare example). I use it at work for testing and different automation scripts or experimentation I do with different internal and external APIs. I use it for my automation needs integrating a bunch of APIs together into a pipeline.

Finally, a piece of self-promotion 😅, if you use Hurl, and have scripts you wish you could run on a schedule or on-demand as part of your CI pipeline, with comprehensive reports you can view at any time including storing the full responses, have a look into Skybear.NET, and let me know what you like and don’t like.