Request describes an HTTP request: a mandatory method and URL, followed by optional headers.
Then, query parameters, form parameters, multipart form data, cookies, basic authentication and options can be used to configure the HTTP request.
Finally, an optional body can be used to configure the HTTP request body.
GET https://example.org/api/dogs?id=4567
User-Agent: My User Agent
Content-Type: application/json
[BasicAuth]
alice: secret
Headers, if present, follow directly after the method and URL. This allows Hurl format to ‘look like’ the real HTTP format.
Contrary to HTTP headers, other parameters are defined in sections ([Cookies]
, [QueryStringParams]
, [FormParams]
etc...)
These sections are not ordered and can be mixed in any way:
GET https://example.org/api/dogs
User-Agent: My User Agent
[QueryStringParams]
id: 4567
order: newest
[BasicAuth]
alice: secret
GET https://example.org/api/dogs
User-Agent: My User Agent
[BasicAuth]
alice: secret
[QueryStringParams]
id: 4567
order: newest
The last optional part of a request configuration is the request body. Request body must be the last parameter of a request (after headers and request sections). Like headers, body have no explicit marker:
POST https://example.org/api/dogs?id=4567
User-Agent: My User Agent
{
"name": "Ralphy"
}
Mandatory HTTP request method, usually one of GET
, HEAD
, POST
, PUT
, DELETE
, CONNECT
, OPTIONS
,
TRACE
and PATCH
.
Other methods can be used like
QUERY
with the constraint of using only uppercase chars.
Mandatory HTTP request URL.
URL can contain query parameters, even if using a query parameters section is preferred.
# A request with URL containing query parameters.
GET https://example.org/forum/questions/?search=Install%20Linux&order=newest
# A request with query parameters section, equivalent to the first request.
GET https://example.org/forum/questions/
[QueryStringParams]
search: Install Linux
order: newest
Query parameters in query parameter section are not URL encoded.
When query parameters are present in the URL and in a query parameters section, the resulting request will have both parameters.
Optional list of HTTP request headers.
A header consists of a name, followed by a :
and a value.
GET https://example.org/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
Headers directly follow URL, without any section name, contrary to query parameters, form parameters or cookies
Note that a header usually doesn’t start with double quotes. If a header value starts with double quotes, double quotes will be part of the header value:
PATCH https://example.org/file.txt
If-Match: "e0023aa4e"
If-Match
request header will be sent will the following value "e0023aa4e"
(started and ended with double quotes).
Headers must follow directly after the method and URL.
Optional list of query parameters.
A query parameter consists of a field, followed by a :
and a value. The query parameters section starts with
[QueryStringParams]
. Contrary to query parameters in the URL, each value in the query parameters section is not
URL encoded.
GET https://example.org/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: {{custom-search}}
count: 100
If there are any parameters in the URL, the resulted request will have both parameters.
A form parameters section can be used to send data, like HTML form.
This section contains an optional list of key values, each key followed by a :
and a value. Key values will be
encoded in key-value tuple separated by ‘&’, with a ‘=’ between the key and the value, and sent in the body request.
The content type of the request is application/x-www-form-urlencoded
. The form parameters section starts
with [FormParams]
.
POST https://example.org/contact
[FormParams]
default: false
token: {{token}}
email: john.doe@rookie.org
number: 33611223344
Form parameters section can be seen as syntactic sugar over body section (values in form parameters section are not URL encoded.). A oneline string body could be used instead of a forms parameters section.
# Run a POST request with form parameters section:
POST https://example.org/test
[FormParams]
name: John Doe
key1: value1
# Run the same POST request with a body section:
POST https://example.org/test
Content-Type: application/x-www-form-urlencoded
`name=John%20Doe&key1=value1`
When both body section and form parameters section are present, only the body section is taken into account.
A multipart form data section can be used to send data, with key / value and file content (see multipart/form-data on MDN).
The form parameters section starts with [MultipartFormData]
.
POST https://example.org/upload
[MultipartFormData]
field1: value1
field2: file,example.txt;
# One can specify the file content type:
field3: file,example.zip; application/zip
Files are relative to the input Hurl file, and cannot contain implicit parent directory (..
). You can use
--file-root
option to specify the root directory of all file nodes.
Content type can be specified or inferred based on the filename extension:
.gif
: image/gif
,.jpg
: image/jpeg
,.jpeg
: image/jpeg
,.png
: image/png
,.svg
: image/svg+xml
,.txt
: text/plain
,.htm
: text/html
,.html
: text/html
,.pdf
: application/pdf
,.xml
: application/xml
By default, content type is application/octet-stream
.
As an alternative to a [MultipartFormData]
section, multipart forms can also be sent with a multiline string body:
POST https://example.org/upload
Content-Type: multipart/form-data; boundary="boundary"
```
--boundary
Content-Disposition: form-data; name="key1"
value1
--boundary
Content-Disposition: form-data; name="upload1"; filename="data.txt"
Content-Type: text/plain
Hello World!
--boundary
Content-Disposition: form-data; name="upload2"; filename="data.html"
Content-Type: text/html
<div>Hello <b>World</b>!</div>
--boundary--
```
When using a multiline string body to send a multipart form data, files content must be inlined in the Hurl file.
Optional list of session cookies for this request.
A cookie consists of a name, followed by a :
and a value. Cookies are sent per request, and are not added to
the cookie storage session, contrary to a cookie set in a header response. (for instance Set-Cookie: theme=light
). The
cookies section starts with [Cookies]
.
GET https://example.org/index.html
[Cookies]
theme: light
sessionToken: abc123
Cookies section can be seen as syntactic sugar over corresponding request header.
# Run a GET request with cookies section:
GET https://example.org/index.html
[Cookies]
theme: light
sessionToken: abc123
# Run the same GET request with a header:
GET https://example.org/index.html
Cookie: theme=light; sessionToken=abc123
A basic authentication section can be used to perform basic authentication.
Username is followed by a :
and a password. The basic authentication section starts with
[BasicAuth]
. Username and password are not base64 encoded.
# Perform basic authentication with login `bob` and password `secret`.
GET https://example.org/protected
[BasicAuth]
bob: secret
Spaces surrounded username and password are trimmed. If you really want a space in your password (!!), you could use Hurl unicode literals \u{20}.
This is equivalent (but simpler) to construct the request with a Authorization header:
# Authorization header value can be computed with `echo -n 'bob:secret' | base64`
GET https://example.org/protected
Authorization: Basic Ym9iOnNlY3JldA==
Basic authentication allows per request authentication.
If you want to add basic authentication to all the requests of a Hurl file
you can use -u/--user
option.
Optional HTTP body request.
If the body of the request is a JSON string or a XML string, the value can be
directly inserted without any modification. For a text based body that is neither JSON nor XML,
one can use multiline string body that starts with ```
and ends
with ```
. Multiline string body support “language hint” and can be used
to create GraphQL queries.
For a precise byte control of the request body, Base64 encoded string, hexadecimal string or included file can be used to describe exactly the body byte content.
You can set a body request even with a
GET
body, even if this is not a common practice.
The body section must be the last section of the request configuration.
JSON request body is used to set a literal JSON as the request body.
# Create a new doggy thing with JSON body:
POST https://example.org/api/dogs
{
"id": 0,
"name": "Frieda",
"picture": "images/scottish-terrier.jpeg",
"age": 3,
"breed": "Scottish Terrier",
"location": "Lisco, Alabama"
}
JSON request body can be templatized with variables:
# Create a new catty thing with JSON body:
POST https://example.org/api/cats
{
"id": 42,
"lives": {{lives_count}},
"name": "{{name}}"
}
When using JSON request body, the content type application/json
is automatically set.
JSON request body can be seen as syntactic sugar of multiline string body with json
identifier:
# Create a new doggy thing with JSON body:
POST https://example.org/api/dogs
```json
{
"id": 0,
"name": "Frieda",
"picture": "images/scottish-terrier.jpeg",
"age": 3,
"breed": "Scottish Terrier",
"location": "Lisco, Alabama"
}
```
XML request body is used to set a literal XML as the request body.
# Create a new soapy thing XML body:
POST https://example.org/InStock
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 299
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://example.net">
<soap:Header></soap:Header>
<soap:Body>
<m:GetStockPrice>
<m:StockName>GOOG</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
XML request body can be seen as syntactic sugar of multiline string body with xml
identifier:
# Create a new soapy thing XML body:
POST https://example.org/InStock
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 299
SOAPAction: "http://www.w3.org/2003/05/soap-envelope"
```xml
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://example.net">
<soap:Header></soap:Header>
<soap:Body>
<m:GetStockPrice>
<m:StockName>GOOG</m:StockName>
</m:GetStockPrice>
</soap:Body>
</soap:Envelope>
```
Contrary to JSON body, the succinct syntax of XML body can not use variables. If you need to use variables in your XML body, use a simple multiline string body with variables.
GraphQL query uses multiline string body with graphql
identifier:
POST https://example.org/starwars/graphql
```graphql
{
human(id: "1000") {
name
height(unit: FOOT)
}
}
```
GraphQL query body can use GraphQL variables:
POST https://example.org/starwars/graphql
```graphql
query Hero($episode: Episode, $withFriends: Boolean!) {
hero(episode: $episode) {
name
friends @include(if: $withFriends) {
name
}
}
}
variables {
"episode": "JEDI",
"withFriends": false
}
```
GraphQL query, as every multiline string body, can use Hurl variables.
POST https://example.org/starwars/graphql
```graphql
{
human(id: "{{human_id}}") {
name
height(unit: FOOT)
}
}
```
Hurl variables and GraphQL variables can be mixed in the same body.
For text based body that are neither JSON nor XML, one can use multiline string, started and ending with
```
.
POST https://example.org/models
```
Year,Make,Model,Description,Price
1997,Ford,E350,"ac, abs, moon",3000.00
1999,Chevy,"Venture ""Extended Edition""","",4900.00
1999,Chevy,"Venture ""Extended Edition, Very Large""",,5000.00
1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof, loaded",4799.00
```
The standard usage of a multiline string is:
```
line1
line2
line3
```
is evaluated as “line1\nline2\nline3\n”.
Multiline string body can use language identifier, like json
, xml
or graphql
. Depending on the language identifier,
an additional ‘Content-Type’ request header is sent, and the real body (bytes sent over the wire) can be different from the
raw multiline text.
POST https://example.org/api/dogs
```json
{
"id": 0,
"name": "Frieda",
}
```
For text based body that do not contain newlines, one can use oneline string, started and ending with `
.
POST https://example.org/helloworld
`Hello world!`
Base64 body is used to set binary data as the request body.
Base64 body starts with base64,
and end with ;
. MIME’s Base64 encoding is supported (newlines and white spaces may be
present anywhere but are to be ignored on decoding), and =
padding characters might be added.
POST https://example.org
# Some random comments before body
base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIG
FkaXBpc2NpbmcgZWxpdC4gSW4gbWFsZXN1YWRhLCBuaXNsIHZlbCBkaWN0dW0g
aGVuZHJlcml0LCBlc3QganVzdG8gYmliZW5kdW0gbWV0dXMsIG5lYyBydXRydW
0gdG9ydG9yIG1hc3NhIGlkIG1ldHVzLiA=;
Hex body is used to set binary data as the request body.
Hex body starts with hex,
and end with ;
.
PUT https://example.org
# Send a café, encoded in UTF-8
hex,636166c3a90a;
To use the binary content of a local file as the body request, file body can be used. File body starts with
file,
and ends with ;
`
POST https://example.org
# Some random comments before body
file,data.bin;
File are relative to the input Hurl file, and cannot contain implicit parent directory (..
). You can use
--file-root
option to specify the root directory of all file nodes.
Options used to execute this request.
Options such as --location
, --verbose
, --insecure
can be used at the command line and applied to every
request of an Hurl file. An [Options]
section can be used to apply option to only one request (without passing options
to the command line), while other requests are unaffected.
GET https://example.org
# An options section, each option is optional and applied only to this request...
[Options]
aws-sigv4: aws:amz:sts # generate AWS SigV4 Authorization header
cacert: /etc/cert.pem # custom certificate file
cert: /etc/client-cert.pem # client authentication certificate
key: /etc/client-cert.key # client authentication certificate key
compressed: true # request a compressed response
delay: 3s # delay for this request
http3: true # use HTTP/3 protocol version
insecure: true # allow insecure SSL connections and transfers
ipv6: true # use IPv6 addresses
location: true # follow redirection for this request
max-redirs: 10 # maximum number of redirections
output: out.html # dump the response to this file
path-as-is: true # do not handle sequences of /../ or /./ in URL path
retry: 10 # number of retry if HTTP/asserts errors
retry-interval: 500ms # interval between retry
skip: false # skip this request
unix-socket: sock # use Unix socket for transfer
user: bob:secret # use basic authentication
proxy: my.proxy:8012 # define proxy (host:port where host can be an IP address)
variable: country=Italy # define variable country
variable: planet=Earth # define variable planet
verbose: true # allow verbose output
very-verbose: true # allow more verbose output
Variable defined in an
[Options]
section are defined also for the next entries. This is the exception, all other options are defined only for the current request.