Skip to content

Repository files navigation

Request Language

A file format specification for defining HTTP requests, response assertions, and configuration in "request files".

Goals

  • Use HTTP request and response messages
  • Easy to read, write, and diff
  • Lives in source control
  • Just a markdown file
  • Templating with variables, prompts, and secret values
  • Environments with environment specific variable values
  • Client/implementation agnostic
  • Statically typed expression language in the templates

Future Goals

  • Chaining requests
  • Response body mapping/transformation/extraction
  • Authenticated requests (e.g. OAuth2) configuration
  • Project workspaces

Request Files

Request files are templated markdown files containing an HTTP request message, HTTP response message assertion (optional), and configuration (optional).

# HTTP Request Message
The [request](https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages#http_requests) is defined inside of a markdown code fence block with `%request` as the language.
The request is the only required part of the request file.
```%requestGET https://example.com HTTP/1.1```
# HTTP Response Message Assertion
The expected HTTP response message assertion is what the actual response will be compared to. It's written inside of a `%response` markdown code block.
The assertion applies the following matching rules:
- Exact match of status code and text
- Exact match of individual headers
- Exact match of the body
```%responseHTTP/1.1 200 OK```
The request, response, and configuration can be defined in any order.
```%requestGET https://example.com HTTP/1.1```
# Configuration
The configuration defines environments, variables, prompts, and secrets accessible during templating. It's written in a `%config` markdown code block.
```%config# The configuration is written in TOML so comments like this are ignored during parsing.``````%requestGET https://example.com HTTP/1.1```
# Environments & Variables
Variables are declared first then defined in the environment declarations.
Here the variable `var1` is declared then defined in the environments `local` and `prod`.
```%config[[vars]]name = "var1"[envs.local]var1 = "local value"[envs.prod]var1 = "production value"```
The variable `var1` is then templated using `{{:var1}}`.
```%requestGET https://example.com HTTP/1.1x-value: {{:var1}}x-env: {{@env}}```
The environment used at request file execution time can also be templated using `{{@env}}`.
# Default Variable Values
Variables can also have a default value defined.
```%config[[vars]]name = "var1"default = "default value"[envs.local]# No value for `var1` is defined so it will be "default value" in the local environment.[envs.prod]var1 = "production value"``````%requestGET https://example.com HTTP/1.1x-value: {{:var1}}x-env: {{@env}}```
The environment used at request file execution time can also be templated using `{{@env}}`.
# Secrets
Secrets are protected values referenced by a name and declares what secrets will be required. How secret values are fetched is up to client implementations. They can be referenced using the `{{!secret_name}}` syntax.
Secrets are optional but if they are declared, they must be at the top of the config block (due to how TOML parses tables).
```%configsecrets = ["api_key"]``````%requestGET https://example.com HTTP/1.1x-api-key: {{!api_key}}```
# Prompts
Prompts are values provided by the user at request execution time. These are "inputs" to the request file. They can be templated in the request and responses using the `{{?prompt_name}}` syntax.
```%config[[prompts]]name = "tags"``````%requestGET https://example.com/posts?tags={{?tags}} HTTP/1.1```

Examples

See all examples for more request files.

Libraries

Rust

The reqlang crate is a library working with request files.

use reqlang::prelude::*;let request_file_text = fs::read_to_string("./path/to/requestfile.reqlang").expect("Should have been able to read the file");const ast = Ast::from(&request_file_text);const parsed_request_file = parse(&ast).expect("should be a valid request file");

Tooling

build-artifacts

These act as both tooling for request file and reference implementations for clients.

CLI

The reqlang CLI validates and exports requests in to a variety of formats (http, curl, json).

reqlang
Command to work with request files
Usage: reqlang [COMMAND]
Commands:
export Export request to specified format
ast Produce an AST for a request file
parse Parse a request file
run Run a request file
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version

Run

Execute the request from a request file.

Usage: reqlang run [OPTIONS] <path>
Arguments:
<path> Path to request file
Options:
-e, --env <env> Resolve with an environment
-P, --prompt <prompts> Input a prompt value
-S, --secret <secrets> Input a secret value
-f, --format <format> Format the response [default: http] [possible values: http, json, body]
-t, --test Test if the response matches the expected response, if defined
-h, --help Print help
Examples
reqlang run ./examples/valid/status_code.reqlang --prompt status_code=200
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
connection: keep-alive
content-length: 0
server: gunicorn/19.9.0
access-control-allow-credentials: true
access-control-allow-origin: *
Testing Responses

Run the response assertion, if defined in the request file, the response will be compared to the expected response.

reqlang run examples/valid/mismatch_response.reqlang --test

See: mismatch_response.reqlang

HTTP/1.1 200 OK
connection: keep-alive
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true
date: Sun, 02 Feb 2025 03:55:33 GMT
content-type: application/json
content-length: 429
{
"slideshow": {
"author": "Yours Truly",
"date": "date of publication",
"slides": [
{
"title": "Wake up to WonderWidgets!",
"type": "all"
},
{
"items": [
"Why <em>WonderWidgets</em> are great",
"Who <em>buys</em> WonderWidgets"
],
"title": "Overview",
"type": "all"
}
],
"title": "Sample Slide Show"
}
}
Response assertion failed:
-HTTP/1.1 201 Created+HTTP/1.1 200 OK-x-test-value: ...
{
"slideshow": {
- "author": "Yours Truly",+ "author": "Yours Truly",+ "date": "date of publication",
"slides": [
{
"title": "Wake up to WonderWidgets!",
"type": "all"
},
{
"items": [
"Why <em>WonderWidgets</em> are great",
"Who <em>buys</em> WonderWidgets"
],
"title": "Overview",
"type": "all"
}
],
- "title": "Test Slide Show"- },- "extra": true+ "title": "Sample Slide Show"+ }
}
-

Parse

Validate and parse request files. It returns a JSON object with info about the request file: environment names, variables, prompts, secrets, the (untemplated) request itself.

Usage: reqlang parse <path>
Arguments:
<path> Path to request file
Options:
-h, --help Print help
Examples
reqlang parse ./examples/valid/status_code.reqlang
{
"vars": ["test_value"],
"envs": ["prod", "test", "local"],
"prompts": ["prompt_value"],
"secrets": ["super_secret_value"],
"request": {
"verb": "POST",
"target": "https://httpbin.org/post",
"http_version": "1.1",
"headers": [],
"body": "{\n\"env\": \"{{@env}}\",\n\"value\": \"{{:test_value}}\",\n\"prompted_value\": \"{{?prompt_value}}\",\n\"secret_value\": \"{{!super_secret_value}}\"\n}\n\n"
}
}
Filtering

Use tools like jq to extract specific information from the parsed request.

Environment Names

Let a list of environment names defined in the request file.

reqlang parse ./examples/valid/post.reqlang | jq '.envs'
["local", "test", "prod"]
Variables

Let a list of variables provided by the request file.

reqlang parse ./examples/valid/post.reqlang | jq '.vars'
["test_value"]
Prompts

Let a list of prompts required by the request file.

reqlang parse ./examples/valid/post.reqlang | jq '.prompts'
["prompt_value"]
Secrets

Let a list of secrets required by the request file.

reqlang parse ./examples/valid/post.reqlang | jq '.secrets'
["super_secret_value"]
Config Location In Request File

Get the span of the config, if defined, in the request file. Otherwise it's null.

reqlang parse ./examples/valid/post.reqlang | jq '.full.config[1]'
{
"start": 0,
"end": 204
}
Request Location In Request File

Get the span of the request in the request file.

reqlang parse ./examples/valid/post.reqlang | jq '.full.request[1]'
{
"start": 208,
"end": 388
}
Response Location In Request File

Get the span of the response, if defined, in the request file. Otherwise it's null.

reqlang parse ./examples/valid/post.reqlang | jq '.full.response[1]'
null
Ref Locations In Request File

Get the span of all the template references (variables, prompts, secrets, providers), if defined, in the request file.

reqlang parse ./examples/valid/post.reqlang | jq '.full.refs'
[
[
{
"Provider": "env"
},
{
"start": 208,
"end": 388
}
],
[
{
"Variable": "test_value"
},
{
"start": 208,
"end": 388
}
],
[
{
"Prompt": "prompt_value"
},
{
"start": 208,
"end": 388
}
],
[
{
"Secret": "super_secret_value"
},
{
"start": 208,
"end": 388
}
]
]
Validation Errors

If the request file is invalid, a list of errors will be returned instead.

reqlang parse examples/invalid/empty.reqlang
[
{
"range": {
"start": {
"line": 0,
"character": 0
},
"end": {
"line": 0,
"character": 0
}
},
"severity": 1,
"message": "ParseError: Request file is an empty file"
}
]

AST

Produce an AST for a request file.

Usage: reqlang ast <path>
Arguments:
<path> Path to request file
Options:
-h, --help Print help
Examples
reqlang ast examples/valid/as_markdown.reqlang
[
[
{
"Comment": "# Request Files Are Markdown Files\n\nAnything outside of the config, request, or response code blocks is treated as markdown. This lets you document your request files in a way that is easy to read and understand.\n\n## Config\n\nPrompt the user for the `status_code` to return.\n\n"
},
{
"start": 0,
"end": 275
}
],
[
{
"ConfigBlock": [
"[prompts]\n# Status code the response will return\nstatus_code = \"\"",
{
"start": 286,
"end": 352
}
]
},
{
"start": 275,
"end": 355
}
],
[
{
"Comment": "\n\n## Request\n\nThis will respond with the prompted `status_code`.\n\n"
},
{
"start": 355,
"end": 421
}
],
[
{
"RequestBlock": [
"GET https://httpbin.org/status/{{?status_code}} HTTP/1.1",
{
"start": 433,
"end": 490
}
]
},
{
"start": 421,
"end": 493
}
]
]
Filtering
Comments
reqlang ast examples/valid/as_markdown.reqlang | jq 'map(select(.[0] | has("Comment")))'
[
[
{
"Comment": "# Request Files Are Markdown Files\n\nAnything outside of the config, request, or response code blocks is treated as markdown. This lets you document your request files in a way that is easy to read and understand.\n\n## Config\n\nPrompt the user for the `status_code` to return.\n\n"
},
{
"start": 0,
"end": 275
}
],
[
{
"Comment": "\n\n## Request\n\nThis will respond with the prompted `status_code`.\n\n"
},
{
"start": 355,
"end": 421
}
]
]

Export

Parse and template the request file then export it in different formats.

Usage: reqlang export [OPTIONS] <path>
Arguments:
<path> Path to request file
Options:
-e, --env <env> Resolve with an environment
-P, --prompt <prompts> Pass prompt values to resolve with
-S, --secret <secrets> Pass secret values to resolve with
-f, --format <format> Format to export [default: json] [possible values: http, curl, json, body]
-h, --help Print help
Examples
JSON
reqlang export examples/valid/status_code.reqlang --prompt status_code=200 --format json
# This is the same thing
reqlang export examples/valid/status_code.reqlang --prompt status_code=200
{
"verb": "GET",
"target": "https://httpbin.org/status/200",
"http_version": "1.1",
"headers": [],
"body": ""
}
HTTP Request Message
reqlang export examples/valid/status_code.reqlang --prompt status_code=201 --format http
GET https://httpbin.org/status/201 HTTP/1.1
Curl command
reqlang export examples/valid/status_code.reqlang --prompt status_code=400 --format curl
curl https://httpbin.org/status/400 --http1.1 -v
Body Text
reqlang export examples/valid/base64decode.reqlang --format body
HTTPBIN is awesome
Validation Errors

If the request file is invalid or there were errors templating, a list of errors will be returned instead.

reqlang export examples/invalid/empty.reqlang
[
{
"range": {
"start": {
"line": 0,
"character": 0
},
"end": {
"line": 0,
"character": 0
}
},
"severity": 1,
"message": "ParseError: Request file is an empty file"
}
]

CLI in Docker

The reqlang CLI can be run from a docker image.

Building

docker build -t reqlang:0.1.0 .

Running

A directory of request files can be mounted inside the container's /usr/local/src directory to make them accessible.

docker run --rm --read-only \
-v "/$PWD/examples":/usr/local/src/examples:ro \
reqlang:0.1.0 \
export \
./examples/valid/delay.reqlang \
-f curl \
-P seconds=5 | bash
# HTTP/1.1 201 CREATED
# Date: Sat, 14 Dec 2024 19:20:26 GMT
# Content-Type: text/html; charset=utf-8
# Content-Length: 0
# Connection: keep-alive
# Server: gunicorn/19.9.0
# Access-Control-Allow-Origin: *
# Access-Control-Allow-Credentials: true

VS Code

The VS Code extension acts as an in-editor REST client.

VS Code Extension Screenshot

Contributing

Please see CONTRIBUTING.md for details on how to contribute.

Development Log

You can follow the development in this Bluesky thread.

About

A file format specification for defining HTTP requests, response assertions, and associated data/configuration in "request files".

Topics

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages