Exploring Hurl, a command line alternative to Postman
Tags: webdev
Published: 2024-05-28 14:20:44

**Written by [Nwani Victory](https://blog.logrocket.com/author/nwanivictory/)✏️**

GUI-based API clients such as Postman and Insomnia have risen in popularity over time. Despite this, various annual developer surveys show that a large percentage of developers, QA and automation engineers, and API testers still resort to using the command line when testing their APIs. 

If you’re a developer who prefers interacting with APIs through the command line, Hurl is an excellent Postman alternative that improves the DX of working with APIs through the command line. In this article, we’ll go through an in-depth explanation of the Hurl tool, its unique benefits, and how to use it.

## What is Hurl?

Hurl is a command-line tool that enables developers to run and test HTTP requests directly from their command line. Its CLI-based approach offers a lightweight alternative to GUI-based tools like Postman. Hurl supports APIs implemented using various protocols such as REST, GraphQL, and SOAP. 

Under the hood, Hurl utilizes the legendary [cURL CLI tool for HTTP transfers](https://blog.logrocket.com/an-intro-to-curl-the-basics-of-the-transfer-tool/). As a result, it shares various similarities with cURL, including deriving its name from cURL and supporting cURL options. 

Hurl supports a wide variety of operating systems including Windows, Linux, and MacOS. As a CLI tool, Hurl is also available for use within Continuous Integration (CI) pipelines. 

Any HTTP requests you want Hurl to execute are stored in files with the `.hurl` extension. Each request URL within a Hurl file is referred to as an [entry](https://hurl.dev/docs/entry.html). Every entry has at least the request method and the URL. 

Hurl supports having multiple request entries within a single file and will execute them sequentially when the file is run. Also, Hurl supports matching multiple `.hurl` files for execution using regular expressions. You’ll see the benefit of matching multiple files during the code demos later. 

A basic Hurl file contains at least a single URL entry, which you want Hurl to validate against as shown in the next code block. When executed, Hurl will make a GET request to the [Rick and Morty API](https://rickandmortyapi.com/documentation/) to fetch all the characters and print them out:

```rust
GET https://rickandmortyapi.com/api
```

Executing the command above should result in an API response like the following: ![Execute Command Screenshot](https://blog.logrocket.com/wp-content/uploads/2024/05/execute-command_f53601.png) Hurl outputs the API response by default. Considering that, you can manipulate the API response in many ways, such as redirecting it to another [tool like jq](https://blog.logrocket.com/npm-query-better-dependency-management/#usage-in-the-terminal-with-jq) to prettify the JSON result. 

If you have `jq` installed, executing the next command will use the shell pipe operator `|` to pass the response body output from Hurl to `jq` for better formatting:

```json
hurl characters.hurl | jq
```

As you can see below, the data is formatted in a much more readable way than the output we saw before: ![More Readable Hurl Output](https://blog.logrocket.com/wp-content/uploads/2024/05/readable-output.png) As your testing requirements increase, Hurl gives you the ability to expand your Hurl file to test multiple URLs and validate their responses, status codes, and even headers.

## Why use Hurl?

Unlike other API clients such as Postman, Hurl is completely open source, free to use, and community-driven. It leverages cURL to improve the experience of working with APIs from the terminal using a plain text syntax and it gives developers a lot of flexibility to tweak and customize their API requests. 

Hurl offers a very lightweight, portable, and easy-to-install tool that you can use in development environments where the system or storage resources are limited such as cloud-based virtual environments or server workstations. 

Testing your API through a CLI tool presents an opportunity for you to automate the steps and avoid repetitive work whenever you make changes to your API. Hurl provides support for GitHub Actions and BitBucket, enabling developers to include executing their Hurl tests in their CI/CD pipelines.

### Evaluating Hurl as a Postman alternative: Comparison table

If you’re deciding whether to use a GUI-based API client like Postman or a command-line tool like Hurl, the following high-level comparison table may help aid your choice:

<table>

<thead>

<tr>

<th></th>

<th>Hurl</th>

<th>Postman</th>

</tr>

</thead>

<tbody>

<tr>

<td>Pricing</td>

<td>Hurl is a free, open source software with no pricing tier to restrict certain features.</td>

<td>Postman is a paid software and not open source. It however has other free open source tools such as the Newman CLI, and Code Generators.</td>

</tr>

<tr>

<td>Usage</td>

<td>Hurl is fully command-line based with no support for testing APIs through a web browser or desktop application.</td>

<td>Postman provides a web browser and desktop application client for API testing. The Newman CLI from Postman supports API testing through the command line.</td>

</tr>

<tr>

<td>Learning curve</td>

<td>Hurl has a steep learning curve for non-technical users as you need to learn its concepts and syntax.</td>

<td>Postman is better suited for non-technical users as the GUI makes testing APIs easier.</td>

</tr>

<tr>

<td>Complexity</td>

<td>Hurl is less complex to begin using as it does not have an onboarding process.</td>

<td>Postman is often quite complex to get up and running as it prompts you to create an account, create a workspace for the project, and also configure the CLI when used within CI/CD workflows.</td>

</tr>

<tr>

<td>Data privacy</td>

<td>Hurl does not collect or store user or team information. The additional details for your API are stored within the project as environment variables in key-value pairs format.</td>

<td>Postman collects user data and persists your testing preferences, binary files, and environment variables outside your project</td>

</tr>

</tbody>

</table>

At this point, you now know what the Hurl tool is and the benefits it offers to developers who love performing API tests through their CLI. We’ve also discussed some of the drawbacks you should be aware of before diving into Hurl, such as its learning curve — especially for beginners.

If you’re willing to put in some time and effort to get familiar with Hurl, it could be a great and powerful tool in your developer toolbox. Let’s proceed to use Hurl in a demo project.

## Demonstrating Hurl’s features and benefits in action

Let’s see Hurl’s benefits in action by using it to test the public [Rick and Morty API](https://rickandmortyapi.com/documentation/) service. We’ll test the REST and GraphQL endpoints from the Rick and Morty service, alongside the frontend website elements that display all RickandMorty characters and episodes. 

Hurl provides various functions for developers to perform implicit and explicit assertions on their API responses. 

For APIs returning data in JSON format, the [JSONPath](https://goessner.net/articles/JsonPath/) assert allows developers to traverse through a response object and check its values. On the other hand, developers testing services returning data in XML format are to make use of the XPath assert.

### Using Hurl asserts on JSON responses

Execute the following command to create a folder named `RickAndMortyHurl`:

```shell
mkdir RickAndMortyHurl
```

You can also manually create the folder with your preferred name on your computer. The folder will store the Hurl files for testing the Rick and Morty API. 

Create your first Hurl file with the name `characters.hurl` within the project folder and add the content of the next code block into it to expand the first RickAndMorty example:

```rust
GET https://rickandmortyapi.com/api/character
HTTP 200

[Asserts]
jsonpath "$.info.count" exists
jsonpath "$.info.pages" exists
jsonpath "$.results" exists

jsonpath "$.results" count >= 20
```

The code above directs Hurl to make a GET request to the `/character` endpoint of the Rick and Morty API and expect only a 200 response status code. The code also contains an `Asserts` block, which explicitly uses the `jsonpath` assert to check if certain properties exist in the info object, as well as whether the objects in the `results` array are equal to or greater than 20. 

Hurl gives you the ability to customize its execution output by applying its [debug options](https://hurl.dev/docs/tutorial/debug-tips.html) to run the command. In this scenario, you should know more about the execution rather than the API response. Hence, you can apply the [`verbose`](https://hurl.dev/docs/tutorial/debug-tips.html#verbose-mode) and [`no-output`](https://hurl.dev/docs/tutorial/debug-tips.html#verbose-mode:~:text=%24%20hurl%20%2D%2Dverbose-,%2D%2Dno%2Doutput,-basic.hurl%0A*) debug options to the command. 

Execute the following to run the `characters.hurl` file in a verbose mode without printing the JSON response from the Rick and Morty API:

```rust
hurl --verbose --test characters.hurl
```

As shown in the following image, Hurl outputs more details in the verbose mode about the API request being made rather than the API response body: ![More Details Verbose Mode](https://blog.logrocket.com/wp-content/uploads/2024/05/more-details-verbose-mode.png) If any of the asserts fail, Hurl will print out the exact failing line with the received and expected values for its stack trace and pause the execution of the file. 

To test, change any of the predicate values within the `characters.hurl` file and run the file again. 

The following image shows the Hurl stack trace when the expected count value of the objects within the results array is greater than the actual value obtained after the API request: ![Error Assert Failure](https://blog.logrocket.com/wp-content/uploads/2024/05/error-assert-failure.png) Similar to creating Hurl asserts using the jsonpath for JSON data, Hurl also provides you with XPath for capturing data from XML responses. 

Before you begin writing the tests, open the [Rick and Morty](https://rickandmortyapi.com/) website to view its text content. You should see something like the following with some large text and a grid of random Rick and Morty characters: ![Rick and Morty API](https://blog.logrocket.com/wp-content/uploads/2024/05/ricky-and-morty-api.png) Considering that we don’t have access to the codebase for the website as we’re not its developers, we can understand the HTML structure behind it by using the Web Inspector element: ![Web Inspector Element](https://blog.logrocket.com/wp-content/uploads/2024/05/web-inspector.png) As you inspect the HTML elements present on the page, you will observe that the large text is the only H1 element on the page, and the Rick and Morty character cards are within an article element. 

Knowing the elements and their attributes is important when testing XML data as you will often need to filter through to these specific elements before running your assertions. 

Create another hurl file named `rickandmorty-website.hurl` within your Hurl project directory to store the entry for the XML data test. 

Add the content of the following code block to your `rickandmorty-website.hurl` file to direct Hurl to make a request to the Rick and Morty webpage and execute queries on its XML elements:

```rust
# rickandmorty-website.hurl 
GET https://rickandmortyapi.com
HTTP 200

[Asserts]
xpath "//h1" exists
xpath "normalize-space(//h1)" contains "The Rick and Morty API"

xpath "//section" count == 2
xpath "//article" count == 6
```

The asserts block in the code block above will direct Hurl to validate that the Rick and Morty website passes the following conditions:

*   It has at least one H1 element in the DOM
*   The H1 element contains text reading "The Rick and Morty API"
*   It has two section elements and six article elements, each for six Rick and Morty character cards

Execute the command below to run the tests for the Rick and Morty website:

```rust
hurl rickandmorty-website.hurl --test
```

Once the test file runs successfully, you should see the result in your terminal: ![Result In Terminal](https://blog.logrocket.com/wp-content/uploads/2024/05/result-terminal.png) At this point, you are now familiar with executing tests using Hurl. Let’s see how to automate the execution of the tests within [a CI/CD pipeline](https://blog.logrocket.com/best-practices-ci-cd-pipeline-frontend/) such as GitHub Actions.

### Adding Hurl to your CI/CD pipeline

In addition to using unit and integration test suites in CI pipelines, developers often want to test their API endpoints directly using real-world values to ensure the response bodies meet the expected results. If you have this need, Hurl is the perfect choice for you! 

Being a very lightweight and fast API client makes Hurl a perfect choice for CI pipelines as they have limited resources. Developers have the option to use scripts to install the Hurl binary into their CI pipelines or through community-managed actions such as [`install-hurl-cross-platform`](https://github.com/marketplace/actions/install-hurl-cross-platform) and [`setup-hurl`](https://github.com/nikeee/setup-hurl). 

To use GitHub Actions, you need to create your action spec in a `.yml` file within a `.github` root folder and add the following code to it. In a repository, GitHub Actions will use the following specification to execute a workflow run using the defined jobs whenever a pull request is opened or reopened:

```yaml
.github/ci.yml

name: RickAndMorty CI Run

on:
 pull_request:
   types:
     - opened
     - reopened

jobs:
 build:
   runs-on: ubuntu-latest
   permissions:
     contents: read
   steps:
     - name: Checkout
       uses: actions/checkout@v4

     - name: Hurl Integration test
       run: |
         curl --location --remote-name https://github.com/Orange-OpenSource/hurl/releases/download/4.0.0/hurl_4.0.0_amd64.deb
         sudo dpkg -i hurl_4.0.0_amd64.deb
         hurl --test *.hurl --variable URL=https://rickandmortyapi.com
```

Although the workflow above is not ideal — as it’s testing against an external application and not the current changes in the pull request — it gives you an idea of how to set up your workflow. 

Going through the `ci.yml` file, you will observe that the build job is using cURL to download the Hurl V4 binary before installing it with root user privileges. With Hurl installed, the job further executes all the Hurl files using a wildcard `*.hurl` and passes in the target URL as a variable to execute the requests against it. 

Using two curly braces wrapped around a word — like `{{test_var}}` — is the syntax for using variables in Hurl files. 

Variables are used to store and reuse certain values or change them dynamically as you would when running tests against different application environments. They also enable you to read sensitive credentials such as API keys and tokens into your Hurl files without hardcoding them in. 

To improve on the workflow file above, you will need to create a deployment preview flow into your GitHub Action and replace the Rick and Morty website URL with your deploy preview URL.

## Conclusion

Hurl presents a feature-rich, flexible, and lightweight tool for testing your APIs straight out of your terminals, CI/CD pipelines, or environments with limited resources. With Hurl, developers who love their command line and terminals no longer have to feel left out when it comes to API testing or compelled to use GUI API clients! 

In this tutorial, we explored the benefits of Hurl, evaluated it as a Postman alternative, and went through some examples to show Hurl’s features in action. If you have any further questions, feel free to comment them below.

---

##Get set up with LogRocket's modern error tracking in minutes:

1. Visit https://logrocket.com/signup/ to get an app ID.
2. Install LogRocket via NPM or script tag. `LogRocket.init()` must be called client-side, not server-side.

NPM:
```bash
$ npm i --save logrocket 

// Code:

import LogRocket from 'logrocket'; 
LogRocket.init('app/id');
```
Script Tag:
```javascript
Add to your HTML:

<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
```

3.(Optional) Install plugins for deeper integrations with your stack:
*   Redux middleware
*   ngrx middleware
*   Vuex plugin

[Get started now](https://lp.logrocket.com/blg/signup)