[![deploy status](https://github.com/Orange-OpenSource/hurl/workflows/CI/badge.svg)](https://github.com/Orange-OpenSource/hurl/actions)
[![documentation](https://img.shields.io/badge/-documentation-informational)](https://hurl.dev)
# What's Hurl?
Hurl is a command line tool that performs HTTP requests defined in a simple plain text format.
It can perform requests, capture values and evaluate queries on headers and body response.
Hurl is very versatile: it can be used for both fetching data and testing HTTP sessions.
```hurl
# Get home:
GET https://example.net
HTTP/1.1 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
# Do login!
POST https://example.net/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
HTTP/1.1 302
```
Chaining multiple requests is easy:
```hurl
GET https://api.example.net/health
GET https://api.example.net/health
GET https://api.example.net/health
GET https://api.example.net/health
```
# Also an HTTP Test Tool
Hurl can run HTTP requests but can also be used to test HTTP responses.
Different type of queries and predicates are supported, from [XPath](https://en.wikipedia.org/wiki/XPath)
and [JSONPath](https://goessner.net/articles/JsonPath/) on body response, to assert on status code and response headers.
```hurl
GET https://example.net
HTTP/1.1 200
[Asserts]
xpath "normalize-space(//head/title)" equals "Hello world!"
```
It is well adapted for REST/json apis
```hurl
POST https://api.example.net/tests
{
"id": "456",
"evaluate": true
}
HTTP/1.1 200
[Asserts]
jsonpath "$.status" equals "RUNNING" # Check the status code
jsonpath "$.tests" countEquals 25 # Check the number of items
```
and even SOAP apis
```hurl
POST https://example.net/InStock
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
GOOG
HTTP/1.1 200
```
# Documentation
Visit the [Hurl web site](https://hurl.dev) to find out how to install and use Hurl.
- [Installation](https://hurl.dev/docs/installation.html)
- [Samples](https://hurl.dev/docs/samples.html)
- [File Format](https://hurl.dev/docs/entry.html)
# Samples
## Getting Data
A simple GET:
```hurl
GET https://example.net
```
[Doc](https://hurl.dev/docs/request.html#method)
A simple GET with headers:
```hurl
GET https://example.net/news
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0
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
GET https://example.net/news
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0
[QueryStringParams]
order: newest
search: something to search
count: 100
```
Or:
```hurl
GET https://example.net/news?order=newest&search=something%20to%20search&count=100
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0
```
[Doc](https://hurl.dev/docs/request.html#query-parameters)
## Sending Data
### Sending HTML Form Datas
```hurl
POST https://example.net/contact
[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
POST https://example.net/upload
[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
POST https://api.example.net/tests
{
"id": "456",
"evaluate": true
}
```
[Doc](https://hurl.dev/docs/request.html#json-body)
With a local file:
```hurl
POST https://api.example.net/tests
Content-Type: application/json
file,data.json;
```
[Doc](https://hurl.dev/docs/request.html#file-body)
### Templating a JSON/XML Body
Using templates with [JSON body](https://hurl.dev/docs/request.html#json-body) or [XML body](https://hurl.dev/docs/request.html#xml-body)
is not currently supported in Hurl. Besides, you can use templates in [raw string body](https://hurl.dev/docs/request.html#raw-string-body)
with variables to send a JSON or XML body:
~~~hurl
PUT https://api.example.net/hits
Content-Type: application/json
```
{
"key0": "{{a_string}}",
"key1": {{a_bool}},
"key2": {{a_null}},
"key3": {{a_number}}
}
```
~~~
Variables can be initialized via command line:
```bash
$ hurl --variable key0=apple --variable key1=true --variable key2=null --variable key3=42 test.hurl
```
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
### Testing REST Apis
```hurl
GET https//example.org/order
screencapability: low
HTTP/1.1 200
[Asserts]
jsonpath "$.validated" equals true
jsonpath "$.userInfo.firstName" equals "Franck"
jsonpath "$.userInfo.lastName" equals "Herbert"
jsonpath "$.hasDevice" equals false
jsonpath "$.links" countEquals 12
```
[Doc](https://hurl.dev/docs/asserting-response.html#jsonpath-assert)
### Testing HTML Response
```hurl
GET https://example.com
HTTP/1.1 200
Content-Type: text/html; charset=UTF-8
[Asserts]
xpath "string(/html/head/title)" contains "Example" # Check title
xpath "count(//p)" equals 2 # Check the number of p
xpath "//p" countEquals 2 # Similar assert for p
xpath "boolean(count(//h2))" equals false # Check there is no h2
xpath "//h2" not exists # Similar assert for h2
```
[Doc](https://hurl.dev/docs/asserting-response.html#xpath-assert)
## Others
### Using SOAP Apis
```hurl
POST https://example.net/InStock
Content-Type: application/soap+xml; charset=utf-8
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
GOOG
HTTP/1.1 200
```
[Doc](https://hurl.dev/docs/request.html#xml-body)
### Capturing and Using a CSRF Token
```hurl
GET https://example.net
HTTP/* 200
[Captures]
csrf_token: xpath "string(//meta[@name='_csrf_token']/@content)"
POST https://example.net/login?user=toto&password=1234
X-CSRF-TOKEN: {{csrf_token}}
HTTP/* 302
```
[Doc](https://hurl.dev/docs/capturing-response.html#xpath-capture)
# Building
## linux, osx
Hurl depends on libssl, libcurl and libxml2 native libraries. You will need their development files in your platform.
```shell
# debian based distributions
apt install -y pkg-config libssl-dev libcurl4-openssl-dev libxml2-dev
# redhat based distributions
yum install -y pkg-config gcc openssl-devel libxml2-devel
# arch based distributions
pacman -Sy --noconfirm pkgconf gcc openssl libxml2
# osx
brew install pkg-config gcc openssl libxml2
```
Hurl is written in [Rust](https://www.rust-lang.org/). You should [install](https://www.rust-lang.org/tools/install) the latest stable release.
```shell
curl https://sh.rustup.rs -sSf | sh -s -- -y
source $HOME/.cargo/env
rustc --version
cargo --version
```
clone this project
```shell
git clone https://github.com/Orange-OpenSource/hurl
cd hurl
cargo build --release
./target/release/hurl --version
```
build
```shell
cargo install --path packages/hurl
```
## windows64
please follow the [contrib/windows section](contrib/windows/README.md)
# Feedbacks
Hurl is still in beta, any feedback, suggestion, bugs or improvements are welcome.
```hurl
POST https://hurl.dev/api/feedback
{
"name": "John Doe",
"feedback": "Hurl is awesome !"
}
HTTP/1.1 200
```