# Request

The **Request** is a fundamental building block of HTTL, no surprise there ;).
While the syntax is largely dictated by the HTTP protocol, the goal was to make it more human-friendly rather than purely protocol-centric.

Let’s start with a complete request form and break it down step by step:

```

post https://httl.dev/api/users
Authorization: Bearer token
{
  name: "morpheus",
  job: "leader"
}
as user
assert {
  status: 201,
  headers: {
    "Content-Type": "application/json; charset=utf-8"
  },
  body: {
    name: "morpheus",
    job: "leader"
  }
}
```

## Request line

The first line combines the verb and the path - again, no surprise there.
Both the verb and path should appear on the same line. For simplicity, all verbs are written in lowercase in HTTL but are sent in uppercase.

Below is the list of all verbs supported by HTTL:
`get`, `post`, `put`, `delete`, `patch`, `head`, `options`, `connect`, `trace`, `lock`, `unlock`, `propfind`, `proppatch`, `copy`, `move`, `mkcol`, `mkcalendar`, `acl`, `search`

The path can be either a full URL or a relative path:

```

# Full URL
get https://httl.dev/api/users

# Relative path
@base: https://httl.dev/api
get /users
```

## Headers

HTTP headers are defined on the line following the request line, and they are optional.
The overall syntax does not differ from the HTTP specification. Each header should follow the `key: value` format.

**Note**

For now we don’t support multi-line headers.

Any blank line will separate the header from the original request object.

```

# `Authorization` will be sent as a header
get /users
Authorization: Bearer token

# `Authorization` header does not belongs to the request anymore and became a global header
get /users # this request will fail

Authorization: Bearer token

# this request will be successful because the `Authorization` header is a global header now
get /users
```

More about global headers on the [Header page](/content/docs/guide/header/index.html).

## Body

The body follows the headers, or it can directly follow the request line if there are no headers.
The body is optional. Although the HTTP specification requires a blank line separating the body from the headers, HTTL does not strictly enforce this.
Moreover, you can place the body on the same line as the request line.

```

get /users {
  name: "morpheus",
  job: "leader"
}
```

💡

**Tip**

Yes, HTTL supports a request body for all HTTP verbs, including `GET` and `DELETE`.

### Body types:

- #### **JSON**

This is the default body type unless other modifiers are specified.

HTTL supports both JSON and JavaScript formats for the body.

Additionally, the request is automatically updated with the `Content-Type: application/json` header.

```

post /users {
    # valid
    "name": "morpheus",
    # also valid
    job: "leader"
}
```

**Note**

HTTL does not currently support single quotes for strings; only double quotes are allowed.
We are working on adding support for single quotes.

- #### **URL-Encoded**

For a URL-encoded body, you need to specify the `urlencoded` modifier.

This automatically updates the `Content-Type` header to `application/x-www-form-urlencoded`.
For example, the body:

```

post /users
urlencoded {
    name: "John Doe",
    age: 30
}
```

will be sent as:

```

POST /users
content-type: application/x-www-form-urlencoded

name=John+Doe&age=30
```

As you can see, `urlencoded { name: "John Doe", age: 30 }` is more human-friendly than `name=John+Doe&age=30`.
This is especially beneficial because, on the backend, the body model is typically represented by a class with corresponding fields.
It’s more natural to work with these fields rather than raw body.

- #### **Form-Data**

Similarly, you just need to specify the `formdata` modifier, and the body will be converted to `form-data`.
Additionally, the `Content-Type` header will be updated to `multipart/form-data`.
The body:

```

post /users
formdata {
    name: "John Doe",
    age: 30
}
```

will be sent as

```

POST /users
content-type: content-type: multipart/form-data; boundary=--------------------------752187623518149651908118

----------------------------752187623518149651908118
Content-Disposition: form-data; name="name"

John Doe
  ----------------------------752187623518149651908118
Content-Disposition: form-data; name="age"

30
```

Imagine how much time you could save by not having to write this manually :)

**Note**

For now, we are working to add support for files in the `formdata` body.

- #### **Binary**

For scenarios where you need to send a binary body, you can use the `bin` modifier.

The `Content-Type` header will be automatically updated to `application/octet-stream`.
The body:

```

post /users
bin "path/to/file"
```

will be sent as

```

POST /users
content-type: application/octet-stream

<binary data>
```

- #### **Raw**

And if none of the above suits your needs, you can send the body as raw.
To do so, specify the `raw` modifier.

In this case, no headers will be added to the request.
The body:

```

post /users
raw "some data"
```

will be sent as

```

POST /users

some data
```

## Variables

The entire request response can be stored in a variable using the `as` keyword.
This is useful when you want to use the response in subsequent requests.

```

post /login {
  user: "user"
  password: "password",
}
as auth

Authorization: Bearer {auth.token}

post /users {
  "name": "rob",
  "job": "engineer",
}
```

More about variable on the [Variables page](/content/docs/guide/variables/index.html).

## Assert

The `assert` block is optional and can be used to validate the response of a request.
This feature will be appreciated by those who write a lot of tests for APIs.

It can be used to check the status code, headers, and body of the response.

**Note**

It’a already in the roadmap to add more features to the `assert` block.

```

get /users/1
assert {
  status: 200,
  headers: {
    "Content-Type": "application/json; charset=utf-8"
  },
  body: {
    name: "morpheus",
    job: "leader"
  }
}
```

More about variable on the [Testing page](/content/docs/guide/testing/index.html).

## Multiple Requests

It might sound obvious, but to state it directly: you can include multiple requests in a single file.
Each request is executed in the order it is defined.
HTTL waits for the response of each request before sending the next one.
In the output, you will see the responses of each request in the sequence they were defined.

```

@base: https://httl.dev/api

get /users

post /users {
  name: "morpheus",
  job: "leader"
}

get /users/1

delete /users/1

```

In the end, you will see 4 responses, one for each request.

Last updated on April 2, 2025.
