File based API client for terminal nerds.
If you’ve ever wanted to manage your API workflows like a code repository, easily searching, editing, copying, and deleting request files and variables, hulak is the tool for you. Hulak is a fast, lightweight, file-based API client that lets you make API calls and organize requests and responses using YAML files.
# ────────────────────────────────────────────────────
# Example: test_gql.hk.yaml
# ────────────────────────────────────────────────────
---
method: POST
# 🚨 Keep secrets separate! Avoid hardcoding credentials.
url: "{{.graphqlUrl}}"
headers:
Content-Type: application/json
# 🔍 Dynamically access nested values from another file
# using the `getValueOf` action.
Authorization: Bearer {{getValueOf "data.access_token" "employer_auth.json"}}
body:
graphql:
# đź“‚ Store large JSON, GraphQL, XML, or HTML files separately
# and access them using the `getFile` action.
query: '{{getFile "e2etests/test_collection/test.graphql"}}'
variables:
# 🏷️ Use templating to dynamically construct values.
name: "{{.userName}} of age {{.userAge}}"
age: "{{.userAge}}"# Run the file using secrets from staging.env file
hulak -env staging -f test_gql- Elevator Pitch
- Getting Started
- Flags and Subcommands
- Schema
- Actions
- Auth2.0 (Beta)
- Planned Features
- Support the Project
brew install xaaha/tap/hulak- Run
go install github.com/xaaha/hulak@latest-
You need to install
goin your system -
In order for any utility, installed with
go install, to be available for use, you need the path fromgo env GOPATHto be in the shell’s PATH.• If it’s not, add the following to your shell's configuration file.
export GOPATH=$HOME/go
export PATH=$PATH:$(go env GOPATH)/bin- Then source your shell configuration file
source ~/.zshrcorsource ~/.bashrc
- Clone the repo
- Install required dependencies: Run
go mod tidyin the root of the project - Build the executable with:
go build -o hulak - Move the executable to the path.
- On Mac/Linux:
sudo mv hulak /usr/local/bin/- Verify the project exists in path with:
which hulak
- Verify the project exists in path with:
- On Windows:
- Move the
hulak.exebinary to a folder that is in your PATH. A common location for this isC:\Go\bin(or another directory you've added to your PATH). - To add a folder to your PATH in Windows:
Go to
Control Panel > System and Security > System > Advanced system settings. ClickEnvironment Variables. UnderSystem variables, find thePathvariable and clickEdit. Add the path to your folder (e.g.,C:\Go\bin) and clickOK.
- Move the
- On Mac/Linux:
hulak version
# or
hulak helpCreate a project directory and cd into it. Then Initialize the project
mkdir my_apis & cd my_apis
hulak init
Hulak uses env directory to store secrets (e.g., passwords, client IDs) used in API call. It allows separation between different environments like local, test, and production environments. The hulak init command above sets up the secrets directory structure env/ and also provides an apiOptions.yaml file for your reference.
# to create multiple .env files in the env directory run
hulak init -env staging prodYou can store all secrets in global.env, but for running tests with different credentials, use additional <custom_file_name>.env files like staging.env or prod.env.
If env/global.env is absent, it will prompt you to create one at runtime. For more details read this environment documentation.
# example directory structure
env/
global.env # default and required created with hulak init
prod.env # user defined, could be anything
staging.env # user defined
collection/ # example directory
test.yaml # example api fileIf you use a .env file to store secrets, you might not want to duplicate secrets already stored in your system environment (for example, your shell). To avoid this, you can reference system environment variables in your .env file by using the $ prefix.
For example, if you had an environment variable USER=foo set on your system, and the following was in your <custom_file_name>.env file.
exampleVar = $USER
Using {{.exampleVar}} within a request file, i.e.
# test.yaml
method: Get
url: http://some.api.com/tests?bar={{.exampleVar}}would result in the request targeting http://some.api.com/tests?bar=foo
Then Basic API call looks like test.yaml below. See full documentation on Request Body structure here. More request examples are here.
# test.yaml
method: Get
url: https://jsonplaceholder.typicode.com/todos/1Run the file with
hulak -env global -f test
# or
hulak -env global -fp test.yamlSince global is default environment, we don't need to specify -env global. So, this is the simplest way of running the file.
hulak -f testFile's response is be printed in the console and also saved at the same location as the calling file with _response.json suffix.
Read more about response in response documentation.
{
"body": {
"completed": false,
"id": 1,
"title": "delectus aut autem",
"userId": 1
},
"status": "200 OK"
}| Flag | Description | Usage |
|---|---|---|
-env |
Specify the environment file you want to use for Api Call. If the user flag is absent, it defaults to global. |
-env prod |
-fp |
Represents file-path for the file/directory you want to run. | -fp "./collection/getUsers.yaml" |
-f |
File name (yaml/yml) to run. Hulak searches your directories and subdirectories from the root and finds the matching yaml file(s). If multiple matches are found, they run concurrently | -f graphql |
-debug |
Add debug boolean flag to get the entire request, response, headers, and TLS info about the api request | -debug |
-dir |
Run entire directory concurrently. Only supports (.yaml or .yam) file. All files use the same provided environment | -dir path/to/directory/ |
-dirseq |
Run entire directory one file at a time. Only supports (.yaml or .yam) file. All files use the same provided environment. In nested directory, it is not guranteed that files will run as they appear in the file system. If the order matter, it's recommended to have a directory without nested directories inside it, in which case, files will run alphabetically | -dirseq path/to/directory/ |
| Subcommand | Description | Usage |
|---|---|---|
| help | display help message | hulak help |
| init | Initialize environment directory and files in it | hulak init or hulak init -env global prod staging |
| migrate | migrates postman environment and collection (v2.1 only) files for hulak. | hulak migrate "path/to/environment.json" "path/to/collection.json |
To enable auto-completion for Hulak YAML files, you have the following options:
Note: You need a YAML language server for any of these options to work.
The Hulak schema is now available in the Schema Store. If your editor supports Schema Store (most do, like VS Code and Neovim with yaml-language-server), auto-completion will work automatically for files ending in .hk.yaml or .hk.yml.
If Schema Store is not set up in your editor, use Option 2 or Option 3 below.
You can declare the schema at the top of your YAML file. This can either be a local schema or a schema referenced by a URL. Here are two examples:
# yaml-language-server: $schema=../../assets/schema.json
---OR
# yaml-language-server: $schema=https://raw.githubusercontent.com/xaaha/hulak/refs/heads/main/assets/schema.json
---Alternatively, you can configure your editor to enable auto-completion without needing to declare the schema in each file. For Neovim users, you can find my configuration here.
Once configured, you can simply rename your file to yourFile.hk.yaml for auto-completion.
Actions make it easier to retrieve values from other files. See, actions documentation for more detailed explanation.
# example section
body:
graphql:
query: |
query Hello($name: String!, $age: Int) {
hello(person: { name: $name, age: $age })
}
variables:
name: "{{.userName}} of age {{.userAge}}"
age: "{{.userAge}}".Key is a variable, that is present in one of the .env files. It grabs the value from environemnt files in the env/ directory in the root of the project created above. The value of, Key is replaced during runtime.
In the example above, .userName and .userAge are examples of retrieving key from secrets stored in env/.
# example
url: `{{getValueOf "key" "file_name" }}`getValueOf looks for the value of the key inside the file_name.json file. Since responses of the api requests are saved in file_name_response.json file in the same directory, you don't need to provide _response.json suffix when using getValueOf.
If multiple file_name.json is found, hulak recurces through the directory and uses the first file match. So, it's recommended that you use a unique name for each file.
You can also provide the exact file location instead of file_name as ./e2etests/test_collection/graphql_response.json
"key"and"file_name": Should be surrounded by double quotes (Go template).keyyou are looking for could in a nested object as well. For example,user.namemeans give me the name inside the user's object. You can esacpe the dot (.) with single curly brace like{user.name}. Here,user.nameis considered akey.file_namecould be the only file name or the entire file path from project root. If only name is provided, first match will be used.
# name is inside the user object in the user.json file
name: '{{getValueOf "user.name" "user.json"}}'
# extract the value of name from nested object from provided json file path
name: '{{getValueOf "data.users[0].name" "e2etests/test_collection/graphql_response.json"}}'
# where name is the key in the file
name: `{{getValueOf "name" "user.json"}}`Gets the file content as string and dumps the entire file content in context. It takes file path as an argument. Do not use getFile action to pass token in auth header.
# example
body:
graphql:
query: '{{getFile "e2etests/test_collection/test.graphql"}}'Learn more about these actions here
Hualk supports auth2.0 web-application-flow. Follow the auth2.0 provider instruction to set it up. Read more here
See Features and Fixes Milestone to see all the upcoming, exciting features
If you enjoy the project, please consider supporting it by reporting a bug, suggesting a feature request, or sponsoring the project. Your pull request contributions are also welcome. Feel free to open an issue indicating your interest in tackling a bug or implementing a new feature.