req is a command-line tool for managing and executing HTTP requests using configuration files.
Have you ever needed to:
- Test API endpoints repeatedly during development?
- Share API request configurations with your team?
- Manage different environments (dev, staging, prod) for the same API?
- Document API usage in a simple, executable format?
req solves these problems by letting you define HTTP requests in a TOML file and execute them with a simple command.
cargo install reqCreate a file named req.toml:
[tasks.hello]
GET = 'https://httpbin.org/get'
description = "My first request"Run it:
$ req hello
# Sends GET request to https://httpbin.org/getThat's it! You've just sent your first HTTP request with req.
Create a set of tasks for your API endpoints:
[tasks.list-users]
GET = 'https://api.example.com/users'
description = "Get all users"
[tasks.get-user]
GET = 'https://api.example.com/users/123'
description = "Get specific user"
[tasks.create-user]
POST = 'https://api.example.com/users'
description = "Create new user"
[tasks.create-user.body.json]
name = "John Doe"
email = "john@example.com"List all available tasks:
$ req
list-users Get all users
get-user Get specific user
create-user Create new userExecute any task:
$ req list-users
$ req create-userBearer Token Authentication:
Most modern APIs use Bearer token authentication. Use variables to manage tokens securely:
[variables]
TOKEN = "your-api-token-here"
[tasks.authenticated]
GET = 'https://api.example.com/protected'
[tasks.authenticated.auth]
bearer = "${TOKEN}"Override tokens from command line:
$ req authenticated -v TOKEN=different-tokenBasic Authentication:
For APIs requiring username and password:
[variables]
USERNAME = "admin"
PASSWORD = "secret"
[tasks.basic-auth]
GET = 'https://api.example.com/admin'
[tasks.basic-auth.auth.basic]
username = "${USERNAME}"
password = "${PASSWORD}"Override credentials from command line:
$ req basic-auth -v USERNAME=user -v PASSWORD=passUsing Environment Files:
The recommended way to manage multiple environments is to use .env files:
# .env.dev
BASE_URL=https://dev.api.example.com
API_TOKEN=dev-token-123# .env.prod
BASE_URL=https://api.example.com
API_TOKEN=prod-token-xyz# req.toml
[tasks.api-call]
GET = "${BASE_URL}/endpoint"
[tasks.api-call.auth]
bearer = "${API_TOKEN}"Switch between environments:
$ req api-call -e .env.dev
$ req api-call -e .env.prodAuto-loading .env file:
You can configure req to automatically load a .env file:
[config]
env-file = true # Loads .env by default
[tasks.api-call]
GET = "${BASE_URL}/endpoint"Or specify a custom default env file:
[config]
env-file = ".env.development" # Loads .env.development by defaultUsing Separate Config Files:
Alternatively, you can create separate config files for each environment:
# req.dev.toml
[variables]
BASE_URL = "https://dev.api.example.com"
[tasks.test]
GET = "${BASE_URL}/endpoint"# req.prod.toml
[variables]
BASE_URL = "https://api.example.com"
[tasks.test]
GET = "${BASE_URL}/endpoint"Switch between environments:
$ req test -f req.dev.toml
$ req test -f req.prod.tomlPlain Text:
[tasks.plain]
POST = 'https://httpbin.org/post'
[tasks.plain.body]
plain = "Hello, World!"JSON:
[tasks.json]
POST = 'https://httpbin.org/post'
[tasks.json.body.json]
name = "Alice"
age = 30
active = trueForm Data:
[tasks.form]
POST = 'https://httpbin.org/post'
[tasks.form.body.form]
username = "alice"
password = "secret"Multipart (File Upload):
[tasks.upload]
POST = 'https://httpbin.org/post'
[tasks.upload.body.multipart]
document.file = "/path/to/document.pdf"
description = "My document"[tasks.search]
GET = 'https://api.example.com/search'
[tasks.search.queries]
q = "rust programming"
limit = "10"
sort = "relevance"
[tasks.search.headers]
Accept = "application/json"
User-Agent = "req/1.0"Use --dryrun to see what will be sent:
$ req create-user --dryrunGenerate equivalent curl command:
$ req create-user --curl
curl -X POST 'https://api.example.com/users' \
-H 'Content-Type: application/json' \
-d '{"name":"John Doe","email":"john@example.com"}'Note:
--curldoes not support multipart bodies; use the request directly (without--curl) for file uploads.
Include response headers in output:
$ req get-user -iFor development/testing environments:
[config]
insecure = true
[tasks.dev-api]
GET = 'https://dev.local/api'[config]
redirect = 5 # Follow up to 5 redirects
[tasks.shortened]
GET = 'https://short.url/abc123'Override global config per task:
[config]
redirect = 0
insecure = false
[tasks.special]
GET = 'https://example.com/redirect'
[tasks.special.config]
redirect = 10
insecure = true- See REFERENCE.md for complete configuration reference
- Check out example configurations in the
examples/directory - Run
req --helpfor all available options
- Store sensitive tokens in environment variables and pass them with
-v - Use descriptive task names to make your workflow self-documenting
- Share
req.tomlfiles with your team for consistent API testing - Combine with shell scripts for automated testing workflows
req ships its own JSON Schema for req.toml. Generate it once and point your editor at the file:
req --schema > ~/.config/tombi/req-schema.jsonThe schema always matches the version of req you have installed — re-run the command after upgrading. Configure your editor (e.g. Tombi) to use this schema for req.toml files.
req distinguishes failure categories by exit status so shell scripts and CI
can branch appropriately.
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Internal error (unclassified — should not occur in practice) |
| 2 | Usage error (invalid arguments, unsupported option combination such as --curl with multipart) |
| 3 | Configuration error (TOML parse, env-file load, undefined ${VAR} interpolation, unknown task) |
| 4 | I/O error (config / output / multipart file read or write failure) |
| 5 | Network error (DNS, connection, TLS, redirect limit, timeout) |
| 6 | HTTP error (server returned a non-2xx status) |