Announcing Hurl 4.3.0

The Hurl team is thrilled to announce Hurl 4.3.0 Surfer !

Hurl is a command line tool powered by curl, that runs HTTP requests defined in a simple plain text format:

HTTP 200
header "x-foo" contains "bar"
certificate "Expire-Date" daysAfterNow > 15
jsonpath "$.status" == "RUNNING"    # Check the status code
jsonpath "$.tests" count == 25      # Check the number of items
jsonpath "$.id" matches /\d{4}/     # Check the format of the id

What’s New in This Release

Quality of Life Improvements

Hurl 4.3.0 is about bringing various quality of life improvements. Nothing fancy, but Hurl keeps iterating, improving and increasing usefulness on each new release.

Error display

Errors display have been slightly improved, with request line displayed to give context without having to look in the Hurl source file.

Before 4.3.0:

error: Undefined variable
--> tests_ok/post_file.hurl:6:8
 6 | file,{{filename}};
   |        ^^^^^^^^ you must set the variable filename

With 4.3.0:

error: Undefined variable
--> tests_ok/post_file.hurl:6:8
   | POST http://localhost:8000/post-file
   | ...
 6 | file,{{filename}};
   |        ^^^^^^^^ you must set the variable filename

--netrc, --netrc-file, --netrc-optional

Like its HTTP engine curl, Hurl supports now the classic .netrc file (typically stored in a user’s home directory). With --netrc option, you can tells Hurl to look for and use the .netrc file. --netrc-file is similar to --netrc, except that you can provide the path to the actual file to use.

$ hurl --test --netrc-file /home/foo/.netrc *.hurl

Per request --user

Let’s keep talking about curl options. Like curl, one can use the command line option --user to add basic authentication to all the requests of a Hurl file:

$ hurl --user bob:secret login.hurl

--user option can now be set per request, in an [Options] section:

# Login with Bob is OK
user: bob:secret
location: true
HTTP 200

# Login with Alice is KO
user: alice:secret
location: true
HTTP 401

--user is useful when using AWS Signature Version 4: Amazon S3 authenticated sessions can be set now per request:

aws-sigv4: aws:amz:eu-central-1:foo
user: someAccessKeyId:someSecretKey
HTTP 200

And, last but not least, --user option can use variables:

aws-sigv4: aws:amz:eu-central-1:foo
user: {{login}}:{{password}}
HTTP 200

Like many other Hurl option, --user option can be used in the command line (take effect for all requests of a Hurl file), or per request, with an [Options] section:

# An options section, each option is optional and applied only to this request...
aws-sigv4: aws:amz:sts  # generate AWS SigV4 Authorization header
cacert: /etc/cert.pem   # custom certificate file
compressed: true        # request a compressed response
delay: 3000             # delay in ms for this request
http3: true             # use HTTP/3 protocol version
insecure: true          # allow insecure SSL connections and transfers
ipv6: true              # use IPv6 addresses
location: true          # follow redirection for this request
max-redirs: 10          # maximum number of redirections
output: out.html        # dump the response to this file
path-as-is: true        # do not handle sequences of /../ or /./ in URL path
skip: false             # skip this request
unix-socket: sock       # use Unix socket for transfer
user: bob:secret        # use basic authentication
variable: country=Italy # define variable country
variable: planet=Earth  # define variable planet
verbose: true           # allow verbose output
very-verbose: true      # allow more verbose output

The options documentation and the Hurl man page have been improved to show which option can be used only in command line and which option can be used in command line and in an [Options] section. When option can only be used in command line the option is tagged “cli-only option”. For instance:

    Colorize debug output (the HTTP response output is not colorized).
    This is a cli-only option.

When “cli-only option” is not specified, the option can be set per request within an [Options] section.


One last new option backported from curl, --max-filesize allows to limit the size of HTTP response data (in bytes):

$ hurl --max-filesize 100000

New Predicates: isNumber, isIsoDate

Predicates are used to check HTTP responses:

HTTP 200
jsonpath "$" == "Yours Truly"
jsonpath "$.slideshow.slides[0].title" contains "Wonder"
jsonpath "$.slideshow.slides" count == 2
jsonpath "$" != null
jsonpath "$.slideshow.slides[*].title" includes "Mind Blowing!"

Two new predicates are introduced with 4.3.0:

  • isNumber: a companion to isInteger / isFloat existing predicates to test if a certain value is a number
  • isIsoDate: check if a string value conforms to the RFC-3339 date format YYYY-MM-DDTHH:mm:sssZ
HTTP 200
jsonpath "$.slideshow.version" isNumber
jsonpath "$" isIsoDate
jsonpath "$" == "1937-01-01T12:00:27.87+00:20"

Shell Completion

Hurl now offers shell completion scripts for various shell: bash, fish, zsh and PowerShell. Usually, packet managers package the completion scripts, but you can still install it yourself from Hurl’s GitHub repository.

One More Thing...

One last thing, and this is a pretty big thing (at least for us Surfer) !

In Hurl 4.3.0, we’ve addressed one of our oldest issue, proposed in 2020: a --parallel option!

Parallel GitHub issue Parallel GitHub issue

It has been a long run since this issue, but we always kept in our mind that, at a moment, we want to be able to run Hurl files in parallel. Now, with 4.3.0, we’re introducing an opt-in --parallel option that will enable parallel execution of Hurl files.

In Hurl 4.3.0, running files in test mode is (no change):

$ hurl --test *.hurl

With --parallel, you can choose to run your tests in parallel:

$ hurl --test --parallel *.hurl

To develop this feature, we take a lot of inspiration of the venerable GNU Parallel.

In the parallel mode, each Hurl file is executed on its own thread, sharing nothing with other jobs. There is a thread pool which size is roughly the current amount of CPUs and that can be configured with --jobs option. During parallel execution, standard output and error are buffered for each file and only displayed on screen when a job file is finished. This way, debug logs and messages are never interleaved between execution. Order of execution is not guaranteed in --parallel mode but reports (HTML, TAP, JUnit) keep the input files order.

The parallelism used is multithread sync: the thread pool is instantiated for the whole run, each Hurl file is run in its own thread, synchronously . We’ve not gone through the full multithreaded async route for implementation simplicity. Moreover, there is no additional dependency, only the standard Rust lib with “classic” threads and multiple producers / single consumer channels to communicate between threads.

For the 4.3.0, we’ve marked the --parallel option as “experimental” as we want to have feedbacks on it and insure that everything works as designed. We plan to make this mode of execution the default when executing Hurl files with --test in the Hurl 5.0.0 version.

Give it a try, if you think Hurl is fast, Oh Boy... Wait until you see the new parallel mode!


There are a lot other improvements with Hurl 4.3.0 and also a lot of bug fixes, you can check the complete list of enhancements and bug fixes in our release note.

If you like Hurl, don’t hesitate to give us a star on GitHub or share it on Twitter!

We’ll be happy to hear from you, either for enhancement requests or for sharing your success story using Hurl!