2022-05-19 11:39:34 +03:00
< img src = "https://raw.githubusercontent.com/Orange-OpenSource/hurl/master/art/logo-full-dark.svg?sanitize=true#gh-dark-mode-only" alt = "Hurl Logo" width = "264px" > < img src = "https://raw.githubusercontent.com/Orange-OpenSource/hurl/master/art/logo-full-light.svg?sanitize=true#gh-light-mode-only" alt = "Hurl Logo" width = "264px" >
2020-08-27 10:07:46 +03:00
< br / >
2020-11-08 16:16:20 +03:00
[![deploy status ](https://github.com/Orange-OpenSource/hurl/workflows/CI/badge.svg )](https://github.com/Orange-OpenSource/hurl/actions)
2022-08-11 23:51:17 +03:00
[![coverage ](https://Orange-OpenSource.github.io/hurl/coverage/badges/flat.svg )](https://Orange-OpenSource.github.io/hurl/coverage)
2021-07-03 15:17:29 +03:00
[![Crates.io ](https://img.shields.io/crates/v/hurl.svg )](https://crates.io/crates/hurl)
2022-08-19 12:04:16 +03:00
[![documentation ](https://img.shields.io/badge/-documentation-ff0288 )](https://hurl.dev)
2020-08-27 10:07:46 +03:00
2021-11-12 18:25:13 +03:00
# What's Hurl?
2020-08-27 10:07:46 +03:00
2021-10-22 16:04:50 +03:00
Hurl is a command line tool that runs < b > HTTP requests< / b > defined in a simple < b > plain text format< / b > .
2022-05-31 15:38:37 +03:00
It can perform requests, capture values and evaluate queries on headers and body response. Hurl is very
2021-10-22 16:04:50 +03:00
versatile: it can be used for both < b > fetching data< / b > and < b > testing HTTP< / b > sessions.
2020-08-27 10:07:46 +03:00
```hurl
# Get home:
2022-05-31 15:38:37 +03:00
GET https://example.org
2020-08-27 10:07:46 +03:00
HTTP/1.1 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
# Do login!
2022-05-31 15:38:37 +03:00
POST https://example.org/login?user=toto& password=1234
2020-08-27 10:07:46 +03:00
X-CSRF-TOKEN: {{csrf_token}}
HTTP/1.1 302
```
Chaining multiple requests is easy:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/api/health
GET https://example.org/api/step1
GET https://example.org/api/step2
GET https://example.org/api/step3
2020-08-27 10:07:46 +03:00
```
2021-11-12 18:25:13 +03:00
# Also an HTTP Test Tool
2020-08-27 10:07:46 +03:00
2021-10-22 16:04:50 +03:00
Hurl can run HTTP requests but can also be used to < b > test HTTP responses< / b > .
2022-05-31 15:38:37 +03:00
Different types of queries and predicates are supported, from [XPath] and [JSONPath] on body response,
2021-10-22 16:04:50 +03:00
to assert on status code and response headers.
2020-08-27 10:07:46 +03:00
2021-10-22 16:04:50 +03:00
It is well adapted for < b > REST / JSON apis< / b >
2020-08-27 10:07:46 +03:00
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/api/tests
2020-08-27 10:07:46 +03:00
{
2022-02-11 16:29:06 +03:00
"id": "4568",
2020-08-27 10:07:46 +03:00
"evaluate": true
}
HTTP/1.1 200
[Asserts]
2022-02-15 20:28:49 +03:00
header "X-Frame-Options" == "SAMEORIGIN"
2021-10-22 16:04:50 +03:00
jsonpath "$.status" == "RUNNING" # Check the status code
jsonpath "$.tests" count == 25 # Check the number of items
2022-02-11 16:29:06 +03:00
jsonpath "$.id" matches /\d{4}/ # Check the format of the id
2020-08-27 10:07:46 +03:00
```
2021-10-22 16:04:50 +03:00
< b > HTML content< / b >
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2021-10-22 16:04:50 +03:00
HTTP/1.1 200
[Asserts]
xpath "normalize-space(//head/title)" == "Hello world!"
```
2020-08-27 10:07:46 +03:00
and even SOAP apis
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/InStock
2020-08-27 10:07:46 +03:00
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
2022-05-31 15:38:37 +03:00
< soap:Envelope xmlns:soap = "http://www.w3.org/2003/05/soap-envelope" xmlns:m = "https://example.org" >
2020-08-27 10:07:46 +03:00
< soap:Header > < / soap:Header >
< soap:Body >
< m:GetStockPrice >
< m:StockName > GOOG< / m:StockName >
< / m:GetStockPrice >
< / soap:Body >
< / soap:Envelope >
HTTP/1.1 200
```
2021-02-12 10:52:29 +03:00
Hurl can also be used to test HTTP endpoints performances:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/api/v1/pets
2021-02-12 10:52:29 +03:00
HTTP/1.0 200
[Asserts]
2021-09-11 23:38:55 +03:00
duration < 1000 # Duration in ms
2021-02-12 10:52:29 +03:00
```
2021-10-22 16:04:50 +03:00
And responses bytes content
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/data.tar.gz
2021-10-22 16:04:50 +03:00
HTTP/1.0 200
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```
2021-02-12 10:52:29 +03:00
2021-11-12 18:25:13 +03:00
# Why Hurl?
2021-02-12 10:52:29 +03:00
2021-10-22 16:04:50 +03:00
< ul class = "showcase-container" >
< li > < b > Text Format:< / b > for both devops and developers< / li >
< li > < b > Fast CLI:< / b > a command line for local dev and continuous integration< / li >
< li > < b > Single Binary:< / b > easy to install, with no runtime required< / li >
< / ul >
2021-11-12 18:25:13 +03:00
# Powered by curl
2021-10-22 16:04:50 +03:00
2022-05-31 15:38:37 +03:00
Hurl is a lightweight binary written in [Rust]. Under the hood, Hurl HTTP engine is
powered by [libcurl], one of the most powerful and reliable file transfer library.
With its text file format, Hurl adds syntactic sugar to run and tests HTTP requests,
2021-10-22 16:04:50 +03:00
but it's still the [curl] that we love.
2021-11-12 18:25:13 +03:00
# Feedbacks
2021-10-22 16:04:50 +03:00
2021-12-08 20:19:44 +03:00
[Feedback, suggestion, bugs or improvements] are welcome!
2021-10-22 16:04:50 +03:00
```hurl
POST https://hurl.dev/api/feedback
{
"name": "John Doe",
"feedback": "Hurl is awesome !"
}
HTTP/1.1 200
```
2021-11-12 18:25:13 +03:00
# Resources
2021-02-12 10:52:29 +03:00
2021-10-22 16:04:50 +03:00
[License]
2020-08-27 10:07:46 +03:00
2022-02-10 23:51:21 +03:00
[Blog]
2022-06-13 09:06:13 +03:00
[Tutorial]
2021-10-22 16:04:50 +03:00
[Documentation]
2020-08-27 10:07:46 +03:00
2021-10-22 16:04:50 +03:00
[GitHub]
2020-08-27 10:07:46 +03:00
2021-11-08 17:51:59 +03:00
Table of Contents
=================
* [Samples ](#samples )
* [Getting Data ](#getting-data )
2021-11-20 22:27:44 +03:00
* [HTTP Headers ](#http-headers )
2021-11-08 17:51:59 +03:00
* [Query Params ](#query-params )
2022-02-11 16:29:06 +03:00
* [Basic Authentification ](#basic-authentification )
2021-11-08 17:51:59 +03:00
* [Sending Data ](#sending-data )
* [Sending HTML Form Datas ](#sending-html-form-datas )
* [Sending Multipart Form Datas ](#sending-multipart-form-datas )
* [Posting a JSON Body ](#posting-a-json-body )
* [Templating a JSON / XML Body ](#templating-a-json--xml-body )
* [Testing Response ](#testing-response )
* [Testing Response Headers ](#testing-response-headers )
* [Testing REST Apis ](#testing-rest-apis )
* [Testing HTML Response ](#testing-html-response )
* [Testing Set-Cookie Attributes ](#testing-set-cookie-attributes )
2022-05-12 17:25:29 +03:00
* [Testing Bytes Content ](#testing-bytes-content )
2021-11-08 17:51:59 +03:00
* [Others ](#others )
* [Testing Endpoint Performance ](#testing-endpoint-performance )
* [Using SOAP Apis ](#using-soap-apis )
* [Capturing and Using a CSRF Token ](#capturing-and-using-a-csrf-token )
* [Checking Byte Order Mark (BOM) in Response Body ](#checking-byte-order-mark-bom-in-response-body )
* [Man Page ](#man-page )
* [Name ](#name )
* [Synopsis ](#synopsis )
* [Description ](#description )
* [Hurl File Format ](#hurl-file-format )
* [Capturing values ](#capturing-values )
* [Asserts ](#asserts )
* [Options ](#options )
* [Environment ](#environment )
* [Exit Codes ](#exit-codes )
* [WWW ](#www )
* [See Also ](#see-also )
* [Installation ](#installation )
* [Binaries Installation ](#binaries-installation )
* [Linux ](#linux )
* [Debian / Ubuntu ](#debian--ubuntu )
* [Arch Linux / Manjaro ](#arch-linux--manjaro )
2022-04-13 23:09:33 +03:00
* [NixOS / Nix ](#nixos--nix )
2021-11-08 17:51:59 +03:00
* [macOS ](#macos )
* [Windows ](#windows )
* [Zip File ](#zip-file )
* [Installer ](#installer )
2021-11-12 18:25:13 +03:00
* [Chocolatey ](#chocolatey )
* [Scoop ](#scoop )
* [Windows Package Manager ](#windows-package-manager )
2021-11-08 17:51:59 +03:00
* [Cargo ](#cargo )
2021-12-16 12:32:00 +03:00
* [Docker ](#docker )
2022-05-31 15:38:37 +03:00
* [npm ](#npm )
2021-11-08 17:51:59 +03:00
* [Building From Sources ](#building-from-sources )
* [Build on Linux, macOS ](#build-on-linux-macos )
2022-04-01 15:27:56 +03:00
* [Debian based distributions ](#debian-based-distributions )
* [Red Hat based distributions ](#red-hat-based-distributions )
2022-05-31 15:38:37 +03:00
* [Arch based distributions ](#arch-based-distributions )
2022-04-01 15:27:56 +03:00
* [macOS ](#macos )
2021-11-08 17:51:59 +03:00
* [Build on Windows ](#build-on-windows )
2020-09-04 22:09:30 +03:00
# Samples
2021-12-08 16:27:22 +03:00
To run a sample, edit a file with the sample content, and run Hurl:
2021-02-12 10:52:29 +03:00
2021-11-20 22:27:44 +03:00
```shell
2021-02-12 10:52:29 +03:00
$ vi sample.hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2021-02-12 10:52:29 +03:00
$ hurl sample.hurl
```
2022-06-13 09:06:13 +03:00
By default, Hurl behaves like [curl] and outputs the last HTTP response's [entry]. To have a test
oriented output, you can use [`--test` option]:
```shell
$ hurl --test sample.hurl
```
2022-05-31 15:38:37 +03:00
You can check [Hurl tests suite] for more samples.
2021-10-22 16:04:50 +03:00
2020-09-04 22:09:30 +03:00
## Getting Data
A simple GET:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2020-09-04 22:09:30 +03:00
```
[Doc ](https://hurl.dev/docs/request.html#method )
2021-11-20 22:27:44 +03:00
### HTTP Headers
2020-09-04 22:09:30 +03:00
A simple GET with headers:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/news
2021-10-22 16:04:50 +03:00
User-Agent: Mozilla/5.0
2020-09-04 22:09:30 +03:00
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
```
[Doc ](https://hurl.dev/docs/request.html#headers )
### Query Params
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/news
2020-09-04 22:09:30 +03:00
[QueryStringParams]
order: newest
search: something to search
count: 100
```
Or:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/news?order=newest& search=something%20to%20search& count=100
2020-09-04 22:09:30 +03:00
```
[Doc ](https://hurl.dev/docs/request.html#query-parameters )
2022-02-11 16:29:06 +03:00
### Basic Authentification
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/protected
2022-02-11 16:29:06 +03:00
[BasicAuth]
bob: secret
```
[Doc ](https://hurl.dev/docs/request.html#basic-authentification )
This is equivalent to construct the request with a [Authorization] header:
```hurl
# Authorization header value can be computed with `echo -n 'bob:secret' | base64`
2022-05-31 15:38:37 +03:00
GET https://example.org/protected
2022-02-11 16:29:06 +03:00
Authorization: Basic Ym9iOnNlY3JldA==
```
Basic authentification allows per request authentification.
If you want to add basic authentification to all the request of a Hurl file
you could use [`-u/--user` option].
2020-09-04 22:09:30 +03:00
## Sending Data
### Sending HTML Form Datas
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/contact
2020-09-04 22:09:30 +03:00
[FormParams]
default: false
token: {{token}}
email: john.doe@rookie.org
number: 33611223344
```
[Doc ](https://hurl.dev/docs/request.html#form-parameters )
### Sending Multipart Form Datas
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/upload
2020-09-04 22:09:30 +03:00
[MultipartFormData]
field1: value1
field2: file,example.txt;
# On can specify the file content type:
field3: file,example.zip; application/zip
```
[Doc ](https://hurl.dev/docs/request.html#multipart-form-data )
### Posting a JSON Body
With an inline JSON:
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/api/tests
2020-09-04 22:09:30 +03:00
{
"id": "456",
"evaluate": true
}
```
[Doc ](https://hurl.dev/docs/request.html#json-body )
With a local file:
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/api/tests
2020-09-04 22:09:30 +03:00
Content-Type: application/json
file,data.json;
```
[Doc ](https://hurl.dev/docs/request.html#file-body )
2021-10-22 16:04:50 +03:00
### Templating a JSON / XML Body
2020-09-04 22:09:30 +03:00
2022-05-31 15:38:37 +03:00
Using templates with [JSON body] or [XML body] is not currently supported in Hurl.
2021-10-22 16:04:50 +03:00
Besides, you can use templates in [raw string body] with variables to send a JSON or XML body:
2020-11-10 09:22:48 +03:00
2020-09-04 22:09:30 +03:00
~~~hurl
2022-05-31 15:38:37 +03:00
PUT https://example.org/api/hits
2020-09-04 22:09:30 +03:00
Content-Type: application/json
```
{
"key0": "{{a_string}}",
"key1": {{a_bool}},
"key2": {{a_null}},
"key3": {{a_number}}
}
```
~~~
Variables can be initialized via command line:
2021-11-20 22:27:44 +03:00
```shell
2022-02-11 16:29:06 +03:00
$ hurl --variable a_string=apple \
--variable a_bool=true \
--variable a_null=null \
--variable a_number=42 \
2021-10-22 16:04:50 +03:00
test.hurl
2020-09-04 22:09:30 +03:00
```
Resulting in a PUT request with the following JSON body:
```
{
"key0": "apple",
"key1": true,
"key2": null,
"key3": 42
}
```
[Doc ](https://hurl.dev/docs/request.html#raw-string-body )
## Testing Response
2021-02-12 10:52:29 +03:00
### Testing Response Headers
Use implicit response asserts to test header values:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/index.html
2021-02-12 10:52:29 +03:00
HTTP/1.0 200
Set-Cookie: theme=light
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
```
[Doc ](https://hurl.dev/docs/asserting-response.html#headers )
2021-10-22 16:04:50 +03:00
Or use explicit response asserts with [predicates]:
2021-02-12 10:52:29 +03:00
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2021-02-12 10:52:29 +03:00
HTTP/1.1 302
[Asserts]
header "Location" contains "www.example.net"
```
2021-10-22 16:04:50 +03:00
[Doc ](https://hurl.dev/docs/asserting-response.html#header-assert )
2021-02-12 10:52:29 +03:00
2020-09-04 22:09:30 +03:00
### Testing REST Apis
2021-11-20 22:27:44 +03:00
Asserting JSON body response (node values, collection count etc...) with [JSONPath]:
2021-02-12 10:52:29 +03:00
2020-09-04 22:09:30 +03:00
```hurl
2021-11-20 22:27:44 +03:00
GET https://example.org/order
2020-09-04 22:09:30 +03:00
screencapability: low
HTTP/1.1 200
[Asserts]
2021-09-11 23:38:55 +03:00
jsonpath "$.validated" == true
jsonpath "$.userInfo.firstName" == "Franck"
jsonpath "$.userInfo.lastName" == "Herbert"
jsonpath "$.hasDevice" == false
jsonpath "$.links" count == 12
jsonpath "$.state" != null
2022-02-11 16:29:06 +03:00
jsonpath "$.order" matches "^order-\\d{8}$"
jsonpath "$.order" matches /^order-\d{8}$/ # Alternative syntax with regex litteral
2020-09-04 22:09:30 +03:00
```
[Doc ](https://hurl.dev/docs/asserting-response.html#jsonpath-assert )
2021-12-08 16:27:22 +03:00
2021-02-12 10:52:29 +03:00
Testing status code:
```hurl
2021-11-20 22:27:44 +03:00
GET https://example.org/order/435
2021-02-12 10:52:29 +03:00
HTTP/1.1 200
```
[Doc ](https://hurl.dev/docs/asserting-response.html#version-status )
```hurl
2021-11-20 22:27:44 +03:00
GET https://example.org/order/435
2021-02-12 10:52:29 +03:00
# Testing status code is in a 200-300 range
HTTP/1.1 *
[Asserts]
2021-09-11 23:38:55 +03:00
status >= 200
status < 300
2021-02-12 10:52:29 +03:00
```
[Doc ](https://hurl.dev/docs/asserting-response.html#status-assert )
2020-09-04 22:09:30 +03:00
### Testing HTML Response
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2020-09-04 22:09:30 +03:00
HTTP/1.1 200
Content-Type: text/html; charset=UTF-8
[Asserts]
xpath "string(/html/head/title)" contains "Example" # Check title
2021-10-22 16:04:50 +03:00
xpath "count(//p)" == 2 # Check the number of p
xpath "//p" count == 2 # Similar assert for p
xpath "boolean(count(//h2))" == false # Check there is no h2
xpath "//h2" not exists # Similar assert for h2
2022-02-11 16:29:06 +03:00
xpath "string(//div[1])" matches /Hello.*/
2020-09-04 22:09:30 +03:00
```
[Doc ](https://hurl.dev/docs/asserting-response.html#xpath-assert )
2021-02-12 10:52:29 +03:00
### Testing Set-Cookie Attributes
```hurl
GET http://myserver.com/home
HTTP/1.0 200
[Asserts]
2021-09-11 23:38:55 +03:00
cookie "JSESSIONID" == "8400BAFE2F66443613DC38AE3D9D6239"
cookie "JSESSIONID[Value]" == "8400BAFE2F66443613DC38AE3D9D6239"
2021-02-12 10:52:29 +03:00
cookie "JSESSIONID[Expires]" contains "Wed, 13 Jan 2021"
cookie "JSESSIONID[Secure]" exists
cookie "JSESSIONID[HttpOnly]" exists
2021-09-11 23:38:55 +03:00
cookie "JSESSIONID[SameSite]" == "Lax"
2021-02-12 10:52:29 +03:00
```
[Doc ](https://hurl.dev/docs/asserting-response.html#cookie-assert )
2022-05-12 17:25:29 +03:00
### Testing Bytes Content
Check the SHA-256 response body hash:
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/data.tar.gz
2022-05-12 17:25:29 +03:00
HTTP/* *
[Asserts]
sha256 == hex,039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
```
[Doc ](https://hurl.dev/docs/asserting-response.html#sha-256-assert )
2020-09-04 22:09:30 +03:00
## Others
2021-02-12 10:52:29 +03:00
### Testing Endpoint Performance
```hurl
GET https://sample.org/helloworld
HTTP/* *
[Asserts]
2021-09-11 23:38:55 +03:00
duration < 1000 # Check that response time is less than one second
2021-02-12 10:52:29 +03:00
```
[Doc ](https://hurl.dev/docs/asserting-response.html#duration-assert )
2020-09-04 22:09:30 +03:00
### Using SOAP Apis
```hurl
2022-05-31 15:38:37 +03:00
POST https://example.org/InStock
2020-09-04 22:09:30 +03:00
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
2022-05-31 15:38:37 +03:00
< soap:Envelope xmlns:soap = "http://www.w3.org/2003/05/soap-envelope" xmlns:m = "https://example.org" >
2020-09-04 22:09:30 +03:00
< soap:Header > < / soap:Header >
< soap:Body >
< m:GetStockPrice >
< m:StockName > GOOG< / m:StockName >
< / m:GetStockPrice >
< / soap:Body >
< / soap:Envelope >
HTTP/1.1 200
```
[Doc ](https://hurl.dev/docs/request.html#xml-body )
### Capturing and Using a CSRF Token
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org
2020-09-04 22:09:30 +03:00
HTTP/* 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
2022-05-31 15:38:37 +03:00
POST https://example.org/login?user=toto& password=1234
2020-09-04 22:09:30 +03:00
X-CSRF-TOKEN: {{csrf_token}}
HTTP/* 302
```
[Doc ](https://hurl.dev/docs/capturing-response.html#xpath-capture )
2021-10-22 16:04:50 +03:00
### Checking Byte Order Mark (BOM) in Response Body
```hurl
2022-05-31 15:38:37 +03:00
GET https://example.org/data.bin
2021-10-22 16:04:50 +03:00
HTTP/* 200
[Asserts]
bytes startsWith hex,efbbbf;
```
[Doc ](https://hurl.dev/docs/asserting-response.html#bytes-assert )
# Man Page
## Name
hurl - run and test HTTP requests.
## Synopsis
**hurl** [options] [FILE...]
## Description
**Hurl** is an HTTP client that performs HTTP requests defined in a simple plain text format.
Hurl is very versatile, it enables to chain HTTP requests, capture values from HTTP responses and make asserts.
```
$ hurl session.hurl
```
2022-08-16 13:08:14 +03:00
If no input files are specified, input is read from stdin.
2021-10-22 16:04:50 +03:00
```
$ echo GET http://httpbin.org/get | hurl
{
"args": {},
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip",
"Content-Length": "0",
"Host": "httpbin.org",
"User-Agent": "hurl/0.99.10",
"X-Amzn-Trace-Id": "Root=1-5eedf4c7-520814d64e2f9249ea44e0"
},
"origin": "1.2.3.4",
"url": "http://httpbin.org/get"
}
```
2022-08-16 13:08:14 +03:00
Output goes to stdout by default. For output to a file, use the [`-o, --output` ](#output ) option:
2021-10-22 16:04:50 +03:00
```
$ hurl -o output input.hurl
```
By default, Hurl executes all HTTP requests and outputs the response body of the last HTTP call.
2022-08-16 13:08:14 +03:00
To have a test oriented output, you can use [`--test` ](#test ) option:
2022-06-23 16:22:16 +03:00
```
$ hurl --test *.hurl
```
2021-10-22 16:04:50 +03:00
## Hurl File Format
2022-08-16 13:08:14 +03:00
The Hurl file format is fully documented in [https://hurl.dev/docs/hurl-file.html ](https://hurl.dev/docs/hurl-file.html )
2021-10-22 16:04:50 +03:00
It consists of one or several HTTP requests
```hurl
2022-06-13 09:06:13 +03:00
GET http:/example.org/endpoint1
GET http:/example.org/endpoint2
2021-10-22 16:04:50 +03:00
```
### Capturing values
A value from an HTTP response can be-reused for successive HTTP requests.
A typical example occurs with csrf tokens.
```hurl
2022-06-13 09:06:13 +03:00
GET https://example.org
2021-10-22 16:04:50 +03:00
HTTP/1.1 200
# Capture the CSRF token value from html body.
[Captures]
csrf_token: xpath "normalize-space(//meta[@name='_csrf_token']/@content)"
# Do the login !
2022-06-13 09:06:13 +03:00
POST https://example.org/login?user=toto& password=1234
2021-10-22 16:04:50 +03:00
X-CSRF-TOKEN: {{csrf_token}}
```
2022-08-16 13:08:14 +03:00
More information on captures here [https://hurl.dev/docs/capturing-response.html ](https://hurl.dev/docs/capturing-response.html )
2022-06-23 16:22:16 +03:00
2021-10-22 16:04:50 +03:00
### Asserts
The HTTP response defined in the Hurl session are used to make asserts.
At the minimum, the response includes the asserts on the HTTP version and status code.
```hurl
GET http:/google.com
2022-02-15 20:28:49 +03:00
HTTP/1.1 301
2021-10-22 16:04:50 +03:00
```
It can also include asserts on the response headers
```hurl
GET http:/google.com
2022-02-15 20:28:49 +03:00
HTTP/1.1 301
2021-10-22 16:04:50 +03:00
Location: http://www.google.com
```
You can also include explicit asserts combining query and predicate
```hurl
GET http:/google.com
2022-02-15 20:28:49 +03:00
HTTP/1.1 301
2021-10-22 16:04:50 +03:00
[Asserts]
2022-02-15 20:28:49 +03:00
xpath "string(//title)" == "301 Moved"
2021-10-22 16:04:50 +03:00
```
Thanks to asserts, Hurl can be used as a testing tool to run scenarii.
2022-08-16 13:08:14 +03:00
More information on asserts here [https://hurl.dev/docs/asserting-response.html ](https://hurl.dev/docs/asserting-response.html )
2021-02-13 22:01:47 +03:00
## Options
2022-08-16 13:08:14 +03:00
Options that exist in curl have exactly the same semantic.
Options specified on the command line are defined for every Hurl file's entry.
For instance:
```
$ hurl --location foo.hurl
```
will follow redirection for each entry in `foo.hurl` . You can also define option only for a particular entry with an `[Options]` section. For instance, this Hurl file:
```hurl
GET https://google.com
HTTP/* 301
GET https://google.com
[Options]
location: true
HTTP/* 200
```
will follow redirection only for the second entry.
2021-02-13 22:01:47 +03:00
Option | Description
--- | ---
2022-02-15 20:28:49 +03:00
< a href = "#cacert" id = "cacert" > < code > --cacert< / code > < / a > | Tells curl to use the specified certificate file to verify the peer.< br / > The file may contain multiple CA certificates.< br / > The certificate(s) must be in PEM format.< br / > Normally curl is built to use a default file for this, so this option is typically used to alter that default file.< br / >
2021-10-22 16:04:50 +03:00
< a href = "#color" id = "color" > < code > --color< / code > < / a > | Colorize Output< br / >
< a href = "#compressed" id = "compressed" > < code > --compressed< / code > < / a > | Request a compressed response using one of the algorithms br, gzip, deflate and automatically decompress the content.< br / >
2022-08-16 13:08:14 +03:00
< a href = "#connect-timeout" id = "connect-timeout" >< code > --connect-timeout < seconds> </ code ></ a > | Maximum time in seconds that you allow Hurl's connection to take.< br />< br /> See also [`-m, --max-time` ](#max-time ) option.< br />
< a href = "#cookie" id = "cookie" >< code > -b, --cookie < file> </ code ></ a > | Read cookies from file (using the Netscape cookie file format).< br />< br /> Combined with [`-c, --cookie-jar` ](#cookie-jar ), you can simulate a cookie storage between successive Hurl runs.< br />
< a href = "#cookie-jar" id = "cookie-jar" >< code > -c, --cookie-jar < file> </ code ></ a > | Write cookies to FILE after running the session (only for one session).< br /> The file will be written using the Netscape cookie file format.< br />< br /> Combined with [`-b, --cookie` ](#cookie ), you can simulate a cookie storage between successive Hurl runs.< br />
2021-10-22 16:04:50 +03:00
< a href = "#fail-at-end" id = "fail-at-end" > < code > --fail-at-end< / code > < / a > | Continue executing requests to the end of the Hurl file even when an assert error occurs.< br / > By default, Hurl exits after an assert error in the HTTP response.< br / > < br / > Note that this option does not affect the behavior with multiple input Hurl files.< br / > < br / > All the input files are executed independently. The result of one file does not affect the execution of the other Hurl files.< br / >
< a href = "#file-root" id = "file-root" > < code > --file-root < dir> < / code > < / a > | Set root filesystem to import files in Hurl. This is used for both files in multipart form data and request body.< br / > When this is not explicitly defined, the files are relative to the current directory in which Hurl is running.< br / >
2022-08-16 13:08:14 +03:00
< a href = "#location" id = "location" >< code > -L, --location</ code ></ a > | Follow redirect. You can limit the amount of redirects to follow by using the [`--max-redirs` ](#max-redirs ) option.< br />
2022-05-16 22:07:34 +03:00
< a href = "#glob" id = "glob" > < code > --glob < glob> < / code > < / a > | Specify input files that match the given glob pattern.< br / > < br / > Multiple glob flags may be used. This flag supports common Unix glob patterns like *, ? and []. < br / > However, to avoid your shell accidentally expanding glob patterns before Hurl handles them, you must use single quotes or double quotes around each pattern.< br / >
2021-10-22 16:04:50 +03:00
< a href = "#include" id = "include" > < code > -i, --include< / code > < / a > | Include the HTTP headers in the output (last entry).< br / >
2022-02-15 20:28:49 +03:00
< a href = "#ignore-asserts" id = "ignore-asserts" > < code > --ignore-asserts< / code > < / a > | Ignore all asserts defined in the Hurl file.< br / >
< a href = "#insecure" id = "insecure" > < code > -k, --insecure< / code > < / a > | This option explicitly allows Hurl to perform "insecure" SSL connections and transfers.< br / >
2021-10-22 16:04:50 +03:00
< a href = "#interactive" id = "interactive" > < code > --interactive< / code > < / a > | Stop between requests.< br / > This is similar to a break point, You can then continue (Press C) or quit (Press Q).< br / >
2021-12-08 20:25:15 +03:00
< a href = "#json" id = "json" > < code > --json< / code > < / a > | Output each hurl file result to JSON. The format is very closed to HAR format. < br / >
2021-10-22 16:04:50 +03:00
< a href = "#max-redirs" id = "max-redirs" > < code > --max-redirs < num> < / code > < / a > | Set maximum number of redirection-followings allowed< br / > By default, the limit is set to 50 redirections. Set this option to -1 to make it unlimited.< br / >
2022-08-16 13:08:14 +03:00
< a href = "#max-time" id = "max-time" >< code > -m, --max-time < seconds> </ code ></ a > | Maximum time in seconds that you allow a request/response to take. This is the standard timeout.< br />< br /> See also [`--connect-timeout` ](#connect-timeout ) option.< br />
< a href = "#no-color" id = "no-color" > < code > --no-color< / code > < / a > | Do not colorize output< br / >
2021-12-08 20:25:15 +03:00
< a href = "#no-output" id = "no-output" > < code > --no-output< / code > < / a > | Suppress output. By default, Hurl outputs the body of the last response.< br / >
2021-10-22 16:04:50 +03:00
< a href = "#noproxy" id = "noproxy" > < code > --noproxy < no-proxy-list> < / code > < / a > | Comma-separated list of hosts which do not use a proxy.< br / > Override value from Environment variable no_proxy.< br / >
< a href = "#output" id = "output" > < code > -o, --output < file> < / code > < / a > | Write output to < file > instead of stdout.< br / >
2022-08-16 15:17:44 +03:00
< a href = "#progress" id = "progress" >< code > --progress</ code ></ a > | Print filename and status for each test (on stderr)< br />< br /> Deprecated, use [`--test` ](#test ) or [`--json` ](#json ) instead.< br />
2022-02-15 20:28:49 +03:00
< a href = "#proxy" id = "proxy" > < code > -x, --proxy [protocol://]host[:port]< / code > < / a > | Use the specified proxy.< br / >
2022-02-10 23:51:21 +03:00
< a href = "#report-junit" id = "report-junit" > < code > --report-junit < file> < / code > < / a > | Generate JUNIT < file > .< br / > < br / > If the < file > report already exists, it will be updated with the new test results.< br / >
< a href = "#report-html" id = "report-html" > < code > --report-html < dir> < / code > < / a > | Generate HTML report in dir.< br / > < br / > If the HTML report already exists, it will be updated with the new test results.< br / >
2022-08-16 15:17:44 +03:00
< a href = "#summary" id = "summary" >< code > --summary</ code ></ a > | Print test metrics at the end of the run (on stderr)< br />< br /> Deprecated, use [`--test` ](#test ) or [`--json` ](#json ) instead.< br />
< a href = "#test" id = "test" > < code > --test< / code > < / a > | Activate test mode: the HTTP response is not outputted anymore, progress is reported for each Hurl file tested and a text summary is displayed when all files have been run. < br / >
2022-02-15 20:28:49 +03:00
< a href = "#to-entry" id = "to-entry" > < code > --to-entry < entry-number> < / code > < / a > | Execute Hurl file to ENTRY_NUMBER (starting at 1).< br / > Ignore the remaining of the file. It is useful for debugging a session.< br / >
2021-10-22 16:04:50 +03:00
< a href = "#user" id = "user" > < code > -u, --user < user:password> < / code > < / a > | Add basic Authentication header to each request.< br / >
2022-02-10 23:51:21 +03:00
< a href = "#user-agent" id = "user-agent" > < code > -A, --user-agent < name> < / code > < / a > | Specify the User-Agent string to send to the HTTP server.< br / >
2022-02-15 20:28:49 +03:00
< a href = "#variable" id = "variable" > < code > --variable < name=value> < / code > < / a > | Define variable (name/value) to be used in Hurl templates.< br / >
2022-08-16 13:08:14 +03:00
< a href = "#variables-file" id = "variables-file" >< code > --variables-file < file> </ code ></ a > | Set properties file in which your define your variables.< br />< br /> Each variable is defined as name=value exactly as with [`--variable` ](#variable ) option.< br />< br /> Note that defining a variable twice produces an error.< br />
2022-08-16 15:17:44 +03:00
< a href = "#verbose" id = "verbose" > < code > -v, --verbose< / code > < / a > | Turn on verbose output on standard error stream.< br / > Useful for debugging.< br / > < br / > A line starting with '>' means data sent by Hurl.< br / > A line staring with '< ' means data received by Hurl.< br / > A line starting with '*' means additional info provided by Hurl.< br / > < br / > If you only want HTTP headers in the output, -i, --include might be the option you're looking for.< br / >
2022-08-17 20:00:07 +03:00
< a href = "#very-verbose" id = "very-verbose" >< code > --very-verbose</ code ></ a > | Turn on more verbose output on standard error stream.< br />< br /> In contrast to [`--verbose` ](#verbose ) option, this option outputs the full HTTP body request and response on standard error.< br />
2022-02-15 20:28:49 +03:00
< a href = "#help" id = "help" > < code > -h, --help< / code > < / a > | Usage help. This lists all current command line options with a short description.< br / >
2021-10-22 16:04:50 +03:00
< a href = "#version" id = "version" > < code > -V, --version< / code > < / a > | Prints version information< br / >
2021-02-13 22:01:47 +03:00
## Environment
Environment variables can only be specified in lowercase.
2022-08-16 13:08:14 +03:00
Using an environment variable to set the proxy has the same effect as using the [`-x, --proxy` ](#proxy ) option.
2021-02-13 22:01:47 +03:00
Variable | Description
2021-10-22 16:04:50 +03:00
--- | ---
`http_proxy [protocol://]<host>[:port]` | Sets the proxy server to use for HTTP.< br />
`https_proxy [protocol://]<host>[:port]` | Sets the proxy server to use for HTTPS.< br />
`all_proxy [protocol://]<host>[:port]` | Sets the proxy server to use if no protocol-specific proxy is set.< br />
2022-08-16 13:08:14 +03:00
`no_proxy <comma-separated list of hosts>` | List of host names that shouldn't go through any proxy.< br />
`HURL_name value` | Define variable (name/value) to be used in Hurl templates. This is similar than [`--variable` ](#variable ) and [`--variables-file` ](#variables-file ) options.< br />
`NO_COLOR` | When set to a non-empty string, do not colorize output (see [`--no-color` ](#no-color ) option).< br />
2021-02-13 22:01:47 +03:00
2021-10-22 16:04:50 +03:00
## Exit Codes
2021-02-13 22:01:47 +03:00
Value | Description
2021-10-22 16:04:50 +03:00
--- | ---
`1` | Failed to parse command-line options.< br />
`2` | Input File Parsing Error.< br />
`3` | Runtime error (such as failure to connect to host).< br />
`4` | Assert Error.< br />
## WWW
[https://hurl.dev ](https://hurl.dev )
2021-02-13 22:01:47 +03:00
2020-11-29 18:55:26 +03:00
2021-10-22 16:04:50 +03:00
## See Also
curl(1) hurlfmt(1)
# Installation
## Binaries Installation
### Linux
2022-04-01 15:27:56 +03:00
Precompiled binary is available at [hurl-1.6.1-x86_64-linux.tar.gz]:
2021-10-22 16:04:50 +03:00
```shell
2021-11-20 22:27:44 +03:00
$ INSTALL_DIR=/tmp
2022-04-01 15:27:56 +03:00
$ curl -sL https://github.com/Orange-OpenSource/hurl/releases/download/1.6.1/hurl-1.6.1-x86_64-linux.tar.gz | tar xvz -C $INSTALL_DIR
$ export PATH=$INSTALL_DIR/hurl-1.6.1:$PATH
2021-10-22 16:04:50 +03:00
```
#### Debian / Ubuntu
For Debian / Ubuntu, Hurl can be installed using a binary .deb file provided in each Hurl release.
```shell
2022-04-01 15:27:56 +03:00
$ curl -LO https://github.com/Orange-OpenSource/hurl/releases/download/1.6.1/hurl_1.6.1_amd64.deb
$ sudo dpkg -i hurl_1.6.1_amd64.deb
2021-10-22 16:04:50 +03:00
```
#### Arch Linux / Manjaro
2022-04-13 23:09:33 +03:00
[`hurl-bin` package] for Arch Linux and derived distros is available via [AUR].
#### NixOS / Nix
[NixOS / Nix package] is available on stable channel.
2021-10-22 16:04:50 +03:00
### macOS
2022-04-01 15:27:56 +03:00
Precompiled binary is available at [hurl-1.6.1-x86_64-osx.tar.gz].
2021-10-22 16:04:50 +03:00
Hurl can also be installed with [Homebrew]:
```shell
2021-11-20 22:27:44 +03:00
$ brew install hurl
2021-10-22 16:04:50 +03:00
```
### Windows
#### Zip File
2022-04-01 15:27:56 +03:00
Hurl can be installed from a standalone zip file [hurl-1.6.1-win64.zip]. You will need to update your `PATH` variable.
2021-10-22 16:04:50 +03:00
#### Installer
2022-04-01 15:27:56 +03:00
An installer [hurl-1.6.1-win64-installer.exe] is also available.
2021-11-12 18:25:13 +03:00
#### Chocolatey
2021-11-20 22:27:44 +03:00
```shell
$ choco install hurl
2021-11-12 18:25:13 +03:00
```
#### Scoop
2021-11-20 22:27:44 +03:00
```shell
$ scoop install hurl
2021-11-12 18:25:13 +03:00
```
2021-10-22 16:04:50 +03:00
2021-11-12 18:25:13 +03:00
#### Windows Package Manager
2021-11-20 22:27:44 +03:00
```shell
$ winget install hurl
2021-11-12 18:25:13 +03:00
```
2021-10-22 16:04:50 +03:00
### Cargo
If you're a Rust programmer, Hurl can be installed with cargo.
2021-11-20 22:27:44 +03:00
```shell
$ cargo install hurl
2021-10-22 16:04:50 +03:00
```
2021-12-16 12:32:00 +03:00
### Docker
2022-02-10 23:51:21 +03:00
```shell
2021-12-16 12:32:00 +03:00
$ docker pull orangeopensource/hurl
```
2022-05-31 15:38:37 +03:00
### npm
```shell
$ npm install --save-dev @orangeopensource/hurl
```
2021-10-22 16:04:50 +03:00
## Building From Sources
Hurl sources are available in [GitHub].
### Build on Linux, macOS
2020-11-29 18:55:26 +03:00
2021-02-04 16:04:17 +03:00
Hurl depends on libssl, libcurl and libxml2 native libraries. You will need their development files in your platform.
2020-11-29 18:55:26 +03:00
2022-04-01 15:27:56 +03:00
#### Debian based distributions
2021-02-04 16:04:17 +03:00
```shell
2022-04-13 17:02:55 +03:00
$ apt install -y build-essential pkg-config libssl-dev libcurl4-openssl-dev libxml2-dev
2022-04-01 15:27:56 +03:00
```
2021-02-04 16:04:17 +03:00
2022-04-01 15:27:56 +03:00
#### Red Hat based distributions
```shell
$ yum install -y pkg-config gcc openssl-devel libxml2-devel
```
2021-02-04 16:04:17 +03:00
2022-05-31 15:38:37 +03:00
#### Arch based distributions
2022-03-20 02:31:57 +03:00
2022-04-01 15:27:56 +03:00
```shell
2022-08-17 20:00:07 +03:00
$ pacman -Sy --noconfirm pkgconf gcc glibc openssl libxml2
2022-04-01 15:27:56 +03:00
```
#### macOS
```shell
$ xcode-select --install
$ brew install pkg-config
2020-11-29 18:55:26 +03:00
```
2021-02-04 16:04:17 +03:00
2021-10-22 16:04:50 +03:00
Hurl is written in [Rust]. You should [install] the latest stable release.
2021-02-04 16:04:17 +03:00
```shell
2021-11-20 22:27:44 +03:00
$ curl https://sh.rustup.rs -sSf | sh -s -- -y
$ source $HOME/.cargo/env
$ rustc --version
$ cargo --version
2020-11-29 18:55:26 +03:00
```
2022-04-01 15:27:56 +03:00
Then build hurl:
2021-02-04 16:04:17 +03:00
```shell
2021-11-20 22:27:44 +03:00
$ git clone https://github.com/Orange-OpenSource/hurl
$ cd hurl
$ cargo build --release
$ ./target/release/hurl --version
2020-11-29 18:55:26 +03:00
```
2021-01-05 11:06:14 +03:00
2021-10-22 16:04:50 +03:00
### Build on Windows
Please follow the [contrib on Windows section].
[XPath]: https://en.wikipedia.org/wiki/XPath
[JSONPath]: https://goessner.net/articles/JsonPath/
[Rust]: https://www.rust-lang.org
[curl]: https://curl.se
[the installation section]: https://hurl.dev/docs/installation.html
2021-12-08 20:19:44 +03:00
[Feedback, suggestion, bugs or improvements]: https://github.com/Orange-OpenSource/hurl/issues
2021-10-22 16:04:50 +03:00
[License]: https://hurl.dev/docs/license.html
2022-06-13 09:06:13 +03:00
[Tutorial]: https://hurl.dev/docs/tutorial/your-first-hurl-file.html
2021-12-11 18:34:16 +03:00
[Documentation]: https://hurl.dev/docs/installation.html
2022-02-10 23:51:21 +03:00
[Blog]: https://hurl.dev/blog/
2021-10-22 16:04:50 +03:00
[GitHub]: https://github.com/Orange-OpenSource/hurl
[libcurl]: https://curl.se/libcurl/
[JSON body]: https://hurl.dev/docs/request.html#json-body
[XML body]: https://hurl.dev/docs/request.html#xml-body
[raw string body]: https://hurl.dev/docs/request.html#raw-string-body
[predicates]: https://hurl.dev/docs/asserting-response.html#predicates
[JSONPath]: https://goessner.net/articles/JsonPath/
2021-11-20 22:27:44 +03:00
[Basic authentication]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme
[`Authorization` header]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
2022-05-31 15:38:37 +03:00
[Hurl tests suite]: https://github.com/Orange-OpenSource/hurl/tree/master/integration/tests_ok
2022-02-11 16:29:06 +03:00
[Authorization]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
[`-u/--user` option]: https://hurl.dev/docs/man-page.html#user
2022-06-13 09:06:13 +03:00
[curl]: https://curl.se
[entry]: https://hurl.dev/docs/entry.html
[`--test` option]: https://hurl.dev/docs/man-page.html#test
2021-10-22 16:04:50 +03:00
[GitHub]: https://github.com/Orange-OpenSource/hurl
2022-04-01 15:27:56 +03:00
[hurl-1.6.1-win64.zip]: https://github.com/Orange-OpenSource/hurl/releases/download/1.6.1/hurl-1.6.1-win64.zip
[hurl-1.6.1-win64-installer.exe]: https://github.com/Orange-OpenSource/hurl/releases/download/1.6.1/hurl-1.6.1-win64-installer.exe
[hurl-1.6.1-x86_64-osx.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.6.1/hurl-1.6.1-x86_64-osx.tar.gz
[hurl-1.6.1-x86_64-linux.tar.gz]: https://github.com/Orange-OpenSource/hurl/releases/download/1.6.1/hurl-1.6.1-x86_64-linux.tar.gz
2021-10-22 16:04:50 +03:00
[Homebrew]: https://brew.sh
[AUR]: https://wiki.archlinux.org/index.php/Arch_User_Repository
[`hurl-bin` package]: https://aur.archlinux.org/packages/hurl-bin/
[install]: https://www.rust-lang.org/tools/install
[Rust]: https://www.rust-lang.org
[contrib on Windows section]: https://github.com/Orange-OpenSource/hurl/blob/master/contrib/windows/README.md
2022-04-13 23:09:33 +03:00
[NixOS / Nix package]: https://search.nixos.org/packages?channel=21.11& from=0& size=1& sort=relevance& type=packages& query=hurl
2021-02-04 16:04:17 +03:00