wave provides a simple, scriptable alternative to GUI tools like Postman, making it easy to send HTTP requests, inspect responses, and automate API workflows directly from your shell. And it's written in Rust!
- GET, POST, PUT, PATCH, DELETE methods
- Specify headers and body data inline
- Responses printed in an easy-to-read format
- Save collections of requests via YAML config files and optionally add/overwrite headers and body data when you run them
- Easy integration with other terminal applications
- MCP integration for LLM agents [coming soon!]
brew tap make-wave/tap
brew install make-wave/tap/wavecargo install --path .# Inline requests## GET request
wave get https://httpbin.org/get ## DELETE request with specified header
wave delete https://httpbin.org/delete X-Delete-Reason:cleanup
## POST request with JSON body (default behaviour)
wave post https://httpbin.org/post name=alice age=30
## PUT request with form data body (the Content-Type header is set automatically)
wave put https://httpbin.org/put --form Authorization:Bearer123 foo=bar
## PATCH request with JSON body and custom header
wave patch https://httpbin.org/patch Accept:application/json update=true
# Collection requests## Request get-user-info from .wave/test.yml
wave -c test get-user-info
## Request create-user from .wave/test.yml with additional body data
wave -c test create-user newkey=newvalue
## Override (or inject) a variable defined in the YAML's variables block
wave -c test get-user-info --var user_id=99 --var base_url=https://staging.example.com- Headers: Use
key:valuesyntax, e.g.Authorization:Bearer123 - Body Data: Use
key=valuesyntax, e.g.name=alice. Defaults to JSON. Specify form data with--form. The correctContent-Typeheader is applied automatically. - Collections: Save requests in YAML files in the
.wavedirectory and run them by name. E.g. for a request calledmy_requestin.wave/my_collection.yml:wave -c my_collection my_request - Variable overrides: Use
--var KEY=VALUE(repeatable) on a collection request to override a value from the YAMLvariables:block or inject a new one. CLI overrides win over the YAML values. Accepts--var KEY=VALUEor--var=KEY=VALUE.
variables:
base_url: https://api.example.comauth_token: secret123user_id: 42requests:
- name: get-user-infomethod: GETurl: ${base_url}/users/${user_id}headers:
Authorization: Bearer ${env:API_TOKEN}Accept: application/json
- name: create-usermethod: POSTurl: ${base_url}/usersheaders:
Authorization: Bearer ${env:API_TOKEN}Content-Type: application/jsonbody:
json:
name: Aliceemail: alice@example.com- Use
${varName}to reference variables defined in the file. - Use
${env:VAR_NAME}to reference environment variables. - Place your YAML files in the
.wavedirectory, e.g.,.wave/example_api.yaml. - Run a request with:
wave example_api get-user-info - The collection name is the file name (without the extension).
Run wave --help for full command-line options and usage details.
There are definitely other HTTP client CLIs and at least some of them are definitely very good. Look at httpie, for example! I wanted one that would allow me to store collections in a plaintext format alongside sourcecode for web APIs so that they could be used for testing. Maybe another one already has that feature, but I didn't look very hard because I was excited about building my own.
