rhc
(Rust HTTP Client) is a command-line tool for storing and sending HTTP requests. It fits well into a command-line/terminal-centric workflow, and is designed to allow you to select and dispatch a desired request as quickly as possible, while keeping the requests themselves in simple, easily-editable files that can be checked into source control.
cargo install rhc
You can download binaries from the Github releases page. At the moment only binaries for macOS are available.
Using rhc requires at least one "request definition" file. This type of file is in TOML format and contains information about a single HTTP request you want to send (the URL, method, body, etc.). As an example, try placing the following content in a file with the name test.toml
:
[request]
url = "https://httpbin.org/get"
method = "GET"
Then try running rhc /path/to/test.toml
. rhc will send a GET request to https://httpbin.org/get
, and you should see the response, including the status code, headers, and body, printed to stdout.
Running rhc --help
will show a brief description of available command-line arguments, most of which are explained more fully in this document.
The request
table in the request definition file species the method and URL to use. Both are required.
Valid values for the method
key are "GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH", and "TRACE".
You can specify query parameters in the query
table:
[request]
url = "https://httpbin.org/get"
method = "GET"
[query]
params = [
{ name = "id", value = "12345" }
]
Alternatively, you can specify them directly in request.url
:
[request]
url = "https://httpbin.org/get?id=12345"
method = "GET"
You can specify headers under a headers
table:
[request]
url = "https://httpbin.org/get"
method = "GET"
[headers]
headers = [
{ name = "Accept-Language", value = "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5" },
{ name = "Authorization", value = "Bearer xyz" }
]
You can specify a request body as plain text, a JSON value or URL-encoded data. You must specify which of these body types you want to use under the body.type
key, and the body itself under the body.content
key.
[request]
url = "https://httpbin.org/post"
method = "POST"
# Plain text body
[body]
type = "text"
content = "Some plain text"
[request]
url = "https://httpbin.org/post"
method = "POST"
# JSON body
[body]
type = "json"
content = '''
{
"some_key": "some value",
"a_number": 123,
"nested": {
"inside": true,
"other": null
}
}'''
[request]
url = "https://httpbin.org/post"
method = "POST"
# URL-encoded body
[body]
type = "urlencoded"
content = [
{ name = "key1", value = "something" },
{ name = "あいうえお", value = "猪" }
]
The Content-Type
header on the request will automatically be set to text/plain
, application/json
, or application/x-www-form-urlencoded
, respectively. Note that for a JSON body, it is recommended to use multi-line literal strings (triple single-quotes) to wrap the raw JSON value. This way you can use double quotations to place JSON strings in the body.
Note that multipart/form-data
requests are not directly supported.
An optional metadata
table can provide extra information about the request definition that isn't actually used when sending the request. Currently there is one possible metadata key, which is description
. This optional description will be displayed in rhc's interactive mode (to be explained later in this document).
[metadata]
description = "GET example using httpbin"
[request]
url = "https://httpbin.org/get"
method = "GET"
It's possible to use variables in most parts of the request definition, for values that could change depending on the context in which you're sending the request. Variables are denoted by surrounding them with curly braces. The ways that variables can be bound will be explained later, but first, this example shows all the places that variables can be used:
[request]
url = "https://httpbin.org/post?something={var1}" # In the URL
method = "POST"
[query]
params = [
{ name = "{the_name}", value = "{the_value}" } # In query parameters
]
[headers]
headers = [
{ name = "Authorization", value = "Bearer {token}" } # In headers
]
# In request bodies
[body]
type = "json"
content = '''
{
"some_key": "{something}",
"{something_else}": 123
}'''
One way to bind variables is to use the -b
or --binding
command-line argument:
$ rhc -b token=xyz -b something=12345 definition.toml
The other ways to bind variables involve environments and rhc's interactive mode, which will be explained next.
Environments are predefined groups of variables that are stored in a TOML file. They have this format:
name = "Staging"
variables = [
{ name = "token", value = "xyz" },
{ name = "something", value = "12345" }
]
You can specify an environment file to use with the -e
or --environment
argument:
$ rhc -e staging.toml definition.toml
By doing so, all the variables defined in the environment file will be automatically bound, and specifying them via the command line is not necessary (although you can still do so, and bindings specified via the command line will take higher precedence).
The names and values of variables defined in an environment file must be TOML strings. It's still possible to use variables as, for example, JSON numbers and booleans:
# In the request definition file:
[body]
type = "json"
content = '''
{
"a_number": {var1},
"a_bool": {var2}
}
'''
# In the environment file:
variables = [
{ name = "var1", value = "123" },
{ name = "var2", value = "true" }
]
Rather than specifying a request definition, environment, and bindings via command-line arguments, you can also set all of these by using rhc's interactive mode.
Running rhc
without specifying a request definition file will open an interactive interface where you can select a request definition from among all the TOML files contained in your base definition directly, which is ~/rhc/definitions
by default, but can be customized with a config file. You can organize files under this directory as you like; for example, using subdirectories to represent groupings of request definitions for the same API:
~/rhc/definitions
├── weather_api
│ ├── get_forecast.toml
│ └── get_historical_data.toml
├── twitter
│ ├── post_tweet.toml
│ ├── get_tweets.toml
...
In interactive mode, rhc will initially display a list of all request definition files it can find, along with their descriptions, if present:
You can type freely to filter the list, using fuzzy matching:
Press ENTER to select the currently highlighted request definition file. Pressing TAB or Shift-TAB will change the currently selected environment, cycling through all environment files located in the base environments directory, which is ~/rhc/environments
by default. The name of the currently selected environment is displayed in the prompt. There are also a few more convenient key mappings you can use:
Ctrl-c
will quit rhc without sending any requestCtrl-w
will cut to the start of the current word, Readline-styleCtrl-u
will clear the current queryCtrl-p
orUp
will move the selection upCtrl-n
orDown
will move the selection down
rhc requires that all variables present in the selected request definition file be bound before sending. These bindings are taken first from the selected environment file, and then from the --bind
/ -b
command-line argument (overwriting bindings in the environment file, if there are any overlaps). After this, if any unbound variables remain, you will be prompted to enter their values interactively:
rhc saves a history of what values you have bound to variables in the past, and will display a list of values previously used for the current (variable name, environment) pair. As you type, the displayed list will be filtered based on fuzzy-matching against what you have typed. Pressing ENTER will bind the current variable to what you have entered in the prompt. On the other hand, if you want to re-use a historical value, you can press TAB to switch from "entry mode" to "historical selection" mode, signified by the >>
cursor appearing in the list of historical values. In this mode, pressing ENTER will bind the selected historical value, ignoring whatever is currently typed at the prompt.
Otherwise, the same key mappings described above apply here as well.
rhc will look for an optional configuration file, in this order:
- The file specified with the
--config
argument, if present $XDG_CONFIG_HOME/rhc/config.toml
, ifXDG_CONFIG_HOME
is defined~/.config/rhc/config.toml,
if present
If none of the above files are present, a default configuration will be used. Here's a sample config file with explanations of the settings:
# The directory to scan for request definition files when run in interactive
# mode. Defaults to ~/rhc/definitions
request_definition_directory = "~/rhc/definitions"
# The directory to scan for environment files when run in interactive
# mode. Defaults to ~/rhc/environments
environment_directory = "~/rhc/environments"
# The file to store variable binding history in. Defaults to ~/.rhc_history
history_file = "~/.rhc_history"
# The maximum number of lines to save in the history file. Defaults to 1000.
max_history_items = 1000
# A timeout in seconds for establishing a TCP connection. Defaults to 30 seconds.
connect_timeout_seconds = 30
# A timeout in seconds for reading data. Defaults to 30 seconds.
read_timeout_seconds = 30
# A timeout in seconds for the entire request (until the request body finishes
# tranferring). Defaults to no timeout.
timeout_seconds = 30
# A theme to use to color JSON output. See below for more details. Defaults
# to the "base16-eighties.dark" theme.
theme = "base16-eighties.dark"
# Another way to specify a theme
# theme = "~/rhc/one-half-light.tmTheme"
# Various color settings. See below for more details.
[colors]
default_fg = "blue"
default_bg = "indexed(182)"
prompt_fg = "rgb(100, 150, 200)"
(rhc uses the syntect library for highlighting JSON output. The theme
key in your config file can be either a string that maps to one of the default syntect themes, or a file path that contains a Sublime Text syntax definition. If no theme is specified, the "base16-eighties.dark" theme included in syntect will be used.
Various parts of the interactive rhc UI can be customized. The values can either be one of the basic terminal colors (red
, cyan
, lightblue
, lightmagenta
, etc.), one of the extended 256 terminal colors (specified by number, e.g. indexed(50)
), or an RGB color (specified like rgb(10, 20, 30)
).
The keys available to customize are:
default_fg
: Foreground color for interactive choices that aren't selecteddefault_bg
: Background color for interactive choices that aren't selectedselected_fg
: Foreground color for interactive choices that are selectedselected_bg
: Background color for interactive choices that are selectedprompt_fg
: Foreground color for the promptprompt_bg
: Background color for the promptvariable_fg
: Foreground color for unbound variablesvariable_bg
: Background color for unbound variables
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.