HURL: Run and Test HTTP API Requests

A few weeks ago I saw a front-page Hacker News post on a new text based HTTP runner based on CURL and written in Rust called Hurl. Intriguing! We’ve been looking for a simpler way to run and test API requests against our social API.

First off, if you’re looking to test API calls, there are tons of options ranging from online testing tools, Postman, build your own, etc. Here is a Google search on testing API calls.

testing api calls

These tools are probably awesome, but I want to keep things simple:

  • Call the API endpoints with query or post parameters.
  • Verify a 200 Response.
  • Validate the JSON returned.
  • Call another API endpoint based on the JSON returned in the previous call.

The system should run through all the endpoints and alert if something is wrong; the run could be right before release or after a code change. And since I’m a terminal/CLI lover, I would prefer to run the test at the command prompt – using Warp, my favorite Mac terminal app.

Hurl for Testing API Endpoint

When I saw Hurl, I thought wow, this might be perfect – though there is something to be said for the name.

As Hurl describes themselves,

“”Hurl allows running HTTP requests defined in a plain text format. It can be used to fetch data, or play a scenario (sequence of requests), asserting responses along the way. With its textual format, it is aimed for both devops and developers. With its command-line usage/simple unique binary, it is aimed for both local dev and continuous integration.”

Let’s try Hurl out. You can also see how to run Hurl with script examples.

Basic Hurl Call

First install Hurl on the OS of your choice. Here is with brew on a Mac:

brew install hurl

Now let’s try making a call – we’ll just call and verify a 200 response was returned.

Create a file called basic.hurl in your favorite IDE – not there isn’t a VSCode syntax highlighter, but the Hurl team said they are working on it.

HTTP/1.1 200

In the directory where the basic.hurl file is save, run the command:

hurl --test basic.hurl

The response is:

Hurl response

Error! However, this is good. As you can see the issue is response with HTTP/2. Also note how you get stats on how many files were run, the duration, etc. Just change this in the basic.hurl file and you’re off to the races.

Hurl success response

Advanced Hurl Call

Now for the fun stuff, making POST API calls with a body and asserting the results. For this advanced Hurl example we’ll be making calls to Ayrshare’s social media API to send a post. You can create a free account to your API Key. After creating your account connect at least one social network, such as Twitter.

Create a new file called post.hurl and copy the following code:

# /post POST -------------
Content-Type: application/json
Authorization: Bearer {{API_KEY}}
    "randomPost": true,
    "platforms": [

HTTP/* 200
header "Content-Type" == "application/json; charset=utf-8"
jsonpath "$.status" == "success"
jsonpath "$.errors" count == 0

jsonpath "$.postIds[0].status" == "success"
jsonpath "$.postIds[0].id" exists
jsonpath "$.postIds[0].postUrl" exists
jsonpath "$.postIds[0].platform" == "twitter"

jsonpath "$.id" exists
jsonpath "$.refId" exists
jsonpath "$.post" exists

id: jsonpath "$['id']"
tw_id: jsonpath "$.postIds[0].id"
# -----------------------

Several things are happening. First, the {{API_KEY}} is a variable set in an env file. We keep this in a different file so it can be used with different Hurls.

Set you API key in the file called vars.env:


The next two lines (Content-Type and Authorization) set the header followed by the JSON body of the POST. See the social media API /post endpoint for details on the POST body. This is all the data associated with making the call.

The line with HTTP/* 200 begins the testing (* in place of 1.1 or 2 so any HTTP version will be accepted).


In the [Asserts] section of the file we test the validity of the Header and JSON response. header "Content-Type" checks if the content type correct. For the JSON we must extract the key with jsonpath query, a predicate type, and a predicate value.

For example, jsonpath "$.status" == "success" get the status key and check is the value is equal to “success”. If it is not, an error is thrown.

There are several types of predicates, such as exists and count.


The [Captures] section captures data into variables. The format is:

In our example,

id: jsonpath "$['id']"
tw_id: jsonpath "$.postIds[0].id"

we capture the returned post ID and the Tweet ID that is in an object in an array. We can later use this variables if we want to chain requests with the format {{variable name}}:

# /analytics/post -------
Content-Type: application/json
Authorization: Bearer {{API_KEY}}
    "id": "{{id}}"

Run the Hurl

Finally we need to run the Hurl file at a command prompt, using the --very-verbose flag so we can see all the good stuff happening:

hurl --test --very-verbose --variables-file vars.env post.hurl

and the results:

Hurl post

Happy Hurl

So far so good with Hurl. I’ve found it easy to use and feature rich. Also they seem to be on a regular cadence of releases – always a good sign.

We’ve been writing more test cases these past several weeks and as our development team uses Hurl more we’ll decide if it is a permanent part of our testing suite.

If you want to see more sample Hurl files with chaining, check out Ayrshare’s Hurl files.

— Geoff Bourne, Co-Founder Ayrshare