mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-25 20:12:14 +03:00
660 lines
18 KiB
Markdown
660 lines
18 KiB
Markdown
# Request
|
|
|
|
## Definition
|
|
|
|
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.
|
|
|
|
## Example
|
|
|
|
```hurl
|
|
GET https://example.org/api/dogs?id=4567
|
|
User-Agent: My User Agent
|
|
Content-Type: application/json
|
|
[BasicAuth]
|
|
alice: secret
|
|
```
|
|
|
|
## Structure
|
|
|
|
<div class="hurl-structure-schema">
|
|
<div class="hurl-structure">
|
|
<div class="hurl-structure-col-0">
|
|
<div class="hurl-part-0">
|
|
PUT https://sample.net
|
|
</div>
|
|
<div class="hurl-part-1">
|
|
accept: */*<br>x-powered-by: Express<br>user-agent: Test
|
|
</div>
|
|
<div class="hurl-part-2">
|
|
[QueryStringParams]<br>...
|
|
</div>
|
|
<div class="hurl-part-2">
|
|
[FormParams]<br>...
|
|
</div>
|
|
<div class="hurl-part-2">
|
|
[BasicAuth]<br>...
|
|
</div>
|
|
<div class="hurl-part-2">
|
|
[Cookies]<br>...
|
|
</div>
|
|
<div class="hurl-part-2">
|
|
...
|
|
</div>
|
|
<div class="hurl-part-2">
|
|
...
|
|
</div>
|
|
<div class="hurl-part-3">
|
|
{<br>
|
|
"type": "FOO",<br>
|
|
"value": 356789,<br>
|
|
"ordered": true,<br>
|
|
"index": 10<br>
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="hurl-structure-col-1">
|
|
<div class="hurl-request-explanation-part-0">
|
|
<a href="#method">Method</a> and <a href="#url">URL</a> (mandatory)
|
|
</div>
|
|
<div class="hurl-request-explanation-part-1">
|
|
<br><a href="#headers">HTTP request headers</a> (optional)
|
|
</div>
|
|
<div class="hurl-request-explanation-part-2">
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
</div>
|
|
<div class="hurl-request-explanation-part-2">
|
|
<a href="#query-parameters">Query strings</a>, <a href="#form-parameters">form params</a>, <a href="#cookies">cookies</a>, <a href="#basic-authentication">authentication</a> ...<br>(optional sections, unordered)
|
|
</div>
|
|
<div class="hurl-request-explanation-part-2">
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<br>
|
|
</div>
|
|
<div class="hurl-request-explanation-part-3">
|
|
<br>
|
|
</div>
|
|
<div class="hurl-request-explanation-part-3">
|
|
<a href="#body">HTTP request body</a> (optional)
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
[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:
|
|
|
|
```hurl
|
|
GET https://example.org/api/dogs
|
|
User-Agent: My User Agent
|
|
[QueryStringParams]
|
|
id: 4567
|
|
order: newest
|
|
[BasicAuth]
|
|
alice: secret
|
|
```
|
|
|
|
```hurl
|
|
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:
|
|
|
|
```hurl
|
|
POST https://example.org/api/dogs?id=4567
|
|
User-Agent: My User Agent
|
|
{
|
|
"name": "Ralphy"
|
|
}
|
|
```
|
|
|
|
## Description
|
|
|
|
### Method
|
|
|
|
Mandatory HTTP request method, one of `GET`, `HEAD`, `POST`, `PUT`, `DELETE`, `CONNECT`, `OPTIONS`,
|
|
`TRACE`, `PATCH`, `LINK`, `UNLINK`, `PURGE`, `LOCK`, `UNLOCK`, `PROPFIND`, `VIEW`.
|
|
|
|
### URL
|
|
|
|
Mandatory HTTP request URL.
|
|
|
|
URL can contain query parameters, even if using a [query parameters section] is preferred.
|
|
|
|
```hurl
|
|
# 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.
|
|
|
|
### Headers
|
|
|
|
Optional list of HTTP request headers.
|
|
|
|
A header consists of a name, followed by a `:` and a value.
|
|
|
|
```hurl
|
|
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:
|
|
|
|
```hurl
|
|
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].
|
|
|
|
### Query parameters
|
|
|
|
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.
|
|
|
|
```hurl
|
|
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.
|
|
|
|
### Form 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]`.
|
|
|
|
```hurl
|
|
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.
|
|
|
|
~~~hurl
|
|
# 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.
|
|
|
|
### Multipart Form Data
|
|
|
|
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]`.
|
|
|
|
```hurl
|
|
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`.
|
|
|
|
|
|
### Cookies
|
|
|
|
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]`.
|
|
|
|
```hurl
|
|
GET https://example.org/index.html
|
|
[Cookies]
|
|
theme: light
|
|
sessionToken: abc123
|
|
```
|
|
|
|
Cookies section can be seen as syntactic sugar over corresponding request header.
|
|
|
|
```hurl
|
|
# 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
|
|
```
|
|
|
|
### Basic Authentication
|
|
|
|
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.
|
|
|
|
|
|
```hurl
|
|
# 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:
|
|
|
|
```hurl
|
|
# 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].
|
|
|
|
### Body
|
|
|
|
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 not JSON nor XML,
|
|
one can use [multiline string body] that starts with <code>```</code> and ends
|
|
with <code>```</code>. 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 body
|
|
|
|
JSON request body is used to set a literal JSON as the request body.
|
|
|
|
```hurl
|
|
# 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]:
|
|
|
|
```hurl
|
|
# 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:
|
|
|
|
~~~hurl
|
|
# 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 body
|
|
|
|
XML request body is used to set a literal XML as the request body.
|
|
|
|
~~~hurl
|
|
# 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:
|
|
|
|
~~~hurl
|
|
# 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 succint 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
|
|
|
|
GraphQL query uses [multiline string body] with `graphql` identifier:
|
|
|
|
|
|
~~~hurl
|
|
POST https://example.org/starwars/graphql
|
|
```graphql
|
|
{
|
|
human(id: "1000") {
|
|
name
|
|
height(unit: FOOT)
|
|
}
|
|
}
|
|
```
|
|
~~~
|
|
|
|
GraphQL query body can use [GraphQL variables]:
|
|
|
|
~~~hurl
|
|
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.
|
|
|
|
~~~hurl
|
|
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.
|
|
|
|
|
|
#### Multiline string body
|
|
|
|
For text based body that are not JSON nor XML, one can use multiline string, started and ending with
|
|
<code>```</code>.
|
|
|
|
~~~hurl
|
|
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.
|
|
|
|
~~~hurl
|
|
POST https://example.org/api/dogs
|
|
```json
|
|
{
|
|
"id": 0,
|
|
"name": "Frieda",
|
|
}
|
|
```
|
|
~~~
|
|
|
|
#### Oneline string body
|
|
|
|
For text based body that do not contain newlines, one can use oneline string, started and ending with <code>`</code>.
|
|
|
|
~~~hurl
|
|
POST https://example.org/helloworld
|
|
`Hello world!`
|
|
~~~
|
|
|
|
|
|
#### Base64 body
|
|
|
|
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.
|
|
|
|
```hurl
|
|
POST https://example.org
|
|
# Some random comments before body
|
|
base64,TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIG
|
|
FkaXBpc2NpbmcgZWxpdC4gSW4gbWFsZXN1YWRhLCBuaXNsIHZlbCBkaWN0dW0g
|
|
aGVuZHJlcml0LCBlc3QganVzdG8gYmliZW5kdW0gbWV0dXMsIG5lYyBydXRydW
|
|
0gdG9ydG9yIG1hc3NhIGlkIG1ldHVzLiA=;
|
|
```
|
|
|
|
#### Hex body
|
|
|
|
Hex body is used to set binary data as the request body.
|
|
|
|
Hex body starts with `hex,` and end with `;`.
|
|
|
|
```hurl
|
|
PUT https://example.org
|
|
# Send a café, encoded in UTF-8
|
|
hex,636166c3a90a;
|
|
```
|
|
|
|
|
|
#### File body
|
|
|
|
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 `;``
|
|
|
|
```hurl
|
|
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
|
|
|
|
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.
|
|
|
|
```hurl
|
|
GET https://example.org
|
|
# An options section, each option is optional and applied only to this request...
|
|
[Options]
|
|
cacert: /etc/cert.pem # a custom certificate file
|
|
compressed: true # request a compressed response
|
|
insecure: true # allows insecure SSL connections and transfers
|
|
location: true # follow redirection for this request
|
|
max-redirs: 10 # maximum number of redirections
|
|
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.
|
|
|
|
[method]: #method
|
|
[URL]: #url
|
|
[headers]: #headers
|
|
[Headers]: #headers
|
|
[query parameters]: #query-parameters
|
|
[form parameters]: #form-parameters
|
|
[multipart form data]: #multipart-form-data
|
|
[cookies]: #cookies
|
|
[basic authentication]: #basic-authentication
|
|
[body]: #body
|
|
[query parameters section]: #query-parameters
|
|
[HTML form]: https://developer.mozilla.org/en-US/docs/Learn/Forms
|
|
[multiline string body]: #multiline-string-body
|
|
[oneline string body]: #oneline-string-body
|
|
[body section]: #body
|
|
[multipart/form-data on MDN]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
|
|
[`--file-root` option]: /docs/manual.md#file-root
|
|
[JSON]: https://www.json.org
|
|
[XML]: https://en.wikipedia.org/wiki/XML
|
|
[Base64]: https://en.wikipedia.org/wiki/Base64
|
|
[hexadecimal string]: #hex-body
|
|
[included file]: #file-body
|
|
[`--file-root` option]: /docs/manual.md#file-root
|
|
[`-u/--user` option]: /docs/manual.md#user
|
|
[Hurl unicode literals \u{20}]: /docs/hurl-file.md#special-characters-in-strings
|
|
[Authorization]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
|
|
[`--location`]: /docs/manual.md#location
|
|
[`--verbose`]: /docs/manual.md#verbose
|
|
[`--insecure`]: /docs/manual.md#insecure
|
|
[templatized with variables]: /docs/templates.md#templating-body
|
|
[GraphQL queries]: #graphql-query
|
|
[GraphQL variables]: https://graphql.org/learn/queries/#variables
|
|
[options]: #options
|
|
|