Hurl 7.1.0, the Pretty Edition
The Hurl team is thrilled to announce Hurl 7.1.0 
Hurl is a command line tool powered by curl, that runs HTTP requests defined in a simple plain text format:
GET https://example.org/api/tests/4567
HTTP 200
[Asserts]
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
# Some tests on the HTTP layer:
GET https://example.org
HTTP 200
[Asserts]
header "x-foo" contains "bar"
certificate "Expire-Date" daysAfterNow > 15
ip == "2001:0db8:85a3:0000:0000:8a2e:0370:733"
What’s New in This Release
- JSON Response Automatic prettifying
- New Predicates
isObject,isList - New Supported curl options
- New Filters
utf8Decode,utf8Encode
JSON Response Automatic prettifying
Hurl supports two running modes:
-
the “default” one
hurl books.hurl -
the test-oriented one
hurl --test books.hurl
In both cases, asserts and captures are run, the difference between these two modes is about what is written on standard output and standard error.
With default mode, the last HTTP response is written on standard output, as received from the network. You can use this mode when you want to get data from a server, and you need a kind of workflow to get it. It’s like curl, but it’s easier to chain requests and pass data from response to request (like OAuth, CSRF etc...).
With test mode, no response is written on standard output, but the display is tweaked for a test run, with a succinct summary:
$ hurl --test *.hurl
...
--------------------------------------------------------------------------------
Executed files: 100
Executed requests: 100 (1612.9/s)
Succeeded files: 100 (100.0%)
Failed files: 0 (0.0%)
Duration: 62 ms (0h:0m:0s:62ms)
Starting with Hurl 7.1.0, we’ve improved the default mode, when response is displayed on standard output. If the response is a JSON, we’re displaying now a pretty, colored, indented version of it:
$ hurl books.hurl
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 399
}
}
}
Before Hurl 7.1.0, you can achieve the same result with piping to jq:
$ hurl foo.hurl | jq
Now, you can just run:
$ hurl foo.hurl
and the response will be pretty printed. This improvement adresses one of our top-voted issues since 2023, so we’re very happy to have implemented it in this release!
Under the hood
Prettifying JSON response is optimized to consume the fewest possible ressources, so there is no performance hits for a normal usage, even with big responses.
Some implementation details worth noting:
No Unicode escape transformation
In JSON, characters can be written directly using UTF-8 or using Unicode escapes. For instance, a string containing an emoji can be written like this:
{
"an emoji with UTF-8": "🏝️",
"an emoji with Unicode escapes": "\uD83C\uDFDD"
}
The two strings represent exactly the same Unicode char. With this input, different program will prettify JSON differently. Let’s take jq, the de facto standard to manipulate JSON data, and HTTPie, one of the best HTTP client.
jq, by default, will normalize Unicode escapes, rendering Unicode escapes to their UTF-8 representation:
$ cat island.json | jq
{
"an emoji with UTF-8": "🏝️",
"an emoji with Unicode escapes": "🏝"
}
HTTPie renders also Unicode escapes:
$ http http://localhost:8000/island.json
HTTP/1.0 200 OK
Content-Length: 83
...
{
"an emoji with UTF-8": "🏝️",
"an emoji with Unicode escapes": "🏝"
}
Contrary to jq and HTTPie, Hurl will minimally prettify JSON, just coloring Unicode escapes:
$ echo 'GET http://localhost:8000/island.json' | hurl
{
"an emoji with UTF-8": "🏝️",
"an emoji with Unicode escapes": "\uD83C\uDFDD"
}
The idea is to add colors and indentations, but leave the input source “unchanged” otherwise.
Numbers are left untouched
In JSON, float numbers can be represented in different ways, for instance 1,234 can be written 1234, 1.234e3 or
even 1.234E+3.
Given this input:
{
"scientific_notation_positive": 1.23e4,
"scientific_notation_negative": 6.02e-3,
"scientific_uppercase_E": 9.81E+2
}
jq normalizes numbers, keeping fields order: 1.23e4 becomes 1.23E+4, 6.02e-3 becomes 0.00602 and 9.81E+2
becomes 981.
$ cat numbers.json | jq
{
"scientific_notation_positive": 1.23E+4,
"scientific_notation_negative": 0.00602,
"scientific_uppercase_E": 981
}
HTTPie normalizes numbers differently from jq, and also re-orders field (scientific_notation_negative is now before
scientific_notation_positive):
$ http http://localhost:8000/numbers.json
HTTP/1.0 200 OK
Content-Length: 83
...
{
"scientific_notation_negative": 0.00602,
"scientific_notation_positive": 12300.0,
"scientific_uppercase_E": 981.0
}
With Hurl, once again, we’ve chosen not to normalize anything and just augment user input with colors and spacing:
$ echo 'GET http://localhost:8000/numbers.json'
{
"scientific_notation_positive": 1.23e4,
"scientific_notation_negative": 6.02e-3,
"scientific_uppercase_E": 9.81E+2
}
Which is exactly the JSON response, minus color and spaces:
{
"scientific_notation_positive": 1.23e4,
"scientific_notation_negative": 6.02e-3,
"scientific_uppercase_E": 9.81E+2
}
If Hurl pretty printing is too minimalist for you, you can still pipe Hurl output through jq for instance and it will work.
When Hurl’s output is redirected to a file or through a pipe, all pretty printing is disable, so tools that expect a plain
JSON response will work as usual.
New Predicates isObject, isList
Predicates are used to check HTTP responses:
GET http://httpbin.org/json
HTTP 200
[Asserts]
jsonpath "$.slideshow.author" startsWith "Yours Truly"
jsonpath "$.slideshow.slides[0].title" contains "Wonder"
jsonpath "$.slideshow.slides" count == 2
jsonpath "$.slideshow.date" != null
Two new predicates are introduced with 7.1.0:
isObject: check is a value is an object (when working with JSONPath for instance)isList: check if a value is an array
GET https://example.org/order
HTTP 200
[Asserts]
jsonpath "$.userInfo" isObject
jsonpath "$.userInfo.books" isList
New Supported curl options
Introduced in Hurl 7.0.0, --ntlm and --negotiate
curl options can now be set per request:
GET http://petfactory.com/sharepoint
[Options]
user: alice:1234
ntlm: true
HTTP 200
New Filters utf8Decode, utf8Encode
Filters allow to transform data extracted from HTTP responses. In the following sample, replaceRegex, split,
count and nth are filters that process input; they can be chained to transform values in asserts and captures:
GET https://example.org/api
HTTP 200
[Captures]
name: jsonpath "$.user.id" replaceRegex /\d/ "x"
[Asserts]
header "x-servers" split "," count == 2
header "x-servers" split "," nth 0 == "rec1"
header "x-servers" split "," nth 1 == "rec3"
jsonpath "$.books" count == 12
In Hurl 7.1.0, we’ve added new filters utf8Decode and utf8Encode to encode and decode from bytes to string. In the next
example, we get bytes from a Base64 encoded string, then decode these bytes to a string using UTF-8 encoding:
GET https://example.org/messages
HTTP 200
[Asserts]
# From a Base64 string to UTF-8 bytes to final string
jsonpath "$.bytesInBase64" base64Decode utf8Decode == "Hello World"
That’s all for today!
There are a lot of other improvements with Hurl 7.1.0 and also a lot of bug fixes. Among other things, we have added the following features to 7.1.0:
- new ways to add secrets
- by setting environment variables
HURL_SECRET_my_secret - using secrets files with
--secrets-file
- by setting environment variables
- improve
--testprogress bar to display retry status - small improvments to HTML report
You can check the complete list of enhancements and bug fixes in our release note.
If you like Hurl, don’t hesitate to support us with a star on GitHub and share it on 𝕏 and Bluesky!
We’ll be happy to hear from you, either for enhancement requests or for sharing your success story using Hurl!