🐑 yapi
The API client that lives in your terminal (and your git repo).
Stop clicking through heavy Electron apps just to send a JSON body. yapi is a CLI-first, offline-first, git-friendly API client for HTTP, gRPC, and TCP. It uses simple YAML files to define requests, meaning you can commit them, review them, and run them anywhere.
Try the Playground | View Source
⚡ Install
macOS:
curl -fsSL https://yapi.run/install/mac.sh | bashLinux:
curl -fsSL https://yapi.run/install/linux.sh | bashWindows (PowerShell):
irm https://yapi.run/install/windows.ps1 | iex
Alternative Installation Methods
Using Homebrew (macOS):
brew tap jamierpond/yapi brew install --cask yapi
Using Go:
go install yapi.run/cli/cmd/yapi@latest
From Source:
git clone https://github.com/jamierpond/yapi
cd yapi
make install🚀 Quick Start
-
Create a request file (e.g.,
get-user.yapi.yml):yapi: v1 url: https://jsonplaceholder.typicode.com/users/1 method: GET
-
Run it:
yapi run get-user.yapi.yml
-
See the magic: You get a beautifully highlighted, formatted response.
Note: The
yapi: v1version tag is required at the top of all config files. This enables future schema evolution while maintaining backwards compatibility.
📚 Examples
yapi speaks many protocols. Here is how you define them.
1. Request Chaining & Workflows
Chain multiple requests together, passing data between steps. Build authentication flows, integration tests, or multi-step workflows.
yapi: v1 chain: # Step 1: Login and get token - name: login url: https://api.example.com/auth/login method: POST body: username: "dev_sheep" password: ${PASSWORD} # from environment expect: status: 200 assert: - .token != null # Step 2: Create a post using the token - name: create_post url: https://api.example.com/posts method: POST headers: Authorization: Bearer ${login.token} body: title: "Hello World" tags: - cli - testing author: id: 123 active: true expect: status: 201 assert: - .id != null - .title == "Hello World"
Key features:
- Reference previous step data with
${step_name.field}syntax - Access nested JSON properties:
${login.data.token} - Assertions use JQ expressions that must evaluate to true
- Chains stop on first failure (fail-fast)
2. Environment Configuration
Manage multiple environments (dev, staging, prod) with a single config file. Create a yapi.config.yml:
yapi: v1 default_environment: local environments: local: url: http://localhost:3000 vars: API_KEY: dev_key_123 prod: url: https://api.example.com vars: API_KEY: ${PROD_API_KEY} # from shell env env_file: .env.prod # load vars from file
Then reference in your requests:
yapi: v1 url: ${url}/api/v1/users method: GET headers: Authorization: Bearer ${API_KEY}
Switch environments: yapi run my-request.yapi.yml -e prod
3. Simple HTTP Requests
No more escaping quotes in curl. Just clean YAML.
yapi: v1 url: https://api.example.com/posts method: POST content_type: application/json body: title: "Hello World" tags: - cli - testing
4. Advanced Assertions
Validate complex response structures with JQ-powered assertions.
yapi: v1 url: https://api.example.com/users method: GET expect: status: 200 # or [200, 201] for multiple valid codes assert: - . | length > 0 # array has items - .[0].email != null # first item has email - .[] | .active == true # all items are active
5. JQ Filtering (Built-in!)
Don't grep output. Filter it right in the config.
yapi: v1 url: https://jsonplaceholder.typicode.com/users method: GET # Only show me names and emails, sorted by name jq_filter: "[.[] | {name, email}] | sort_by(.name)"
6. gRPC (Reflection Support)
Stop hunting for .proto files. If your server supports reflection, yapi just works.
yapi: v1 url: grpc://localhost:50051 service: helloworld.Greeter rpc: SayHello body: name: "yapi User"
7. GraphQL
First-class support for queries and variables.
yapi: v1 url: https://countries.trevorblades.com/graphql graphql: | query getCountry($code: ID!) { country(code: $code) { name capital } } variables: code: "BR"
🎛️ Interactive Mode (TUI)
Don't remember the file name? Just run yapi without arguments.
This launches the Interactive TUI. You can fuzzy-search through all your .yapi.yml files in the current directory (and subdirectories) and execute them instantly.
Shell History Integration
For a richer CLI experience, source the yapi shell helper in your .zshrc:
# Add to ~/.zshrc YAPI_ZSH="/path/to/yapi/bin/yapi.zsh" # or wherever you installed yapi [ -f "$YAPI_ZSH" ] && source "$YAPI_ZSH" # Optional: short alias alias a="yapi"
This enables:
- TUI commands in shell history: When you use the interactive TUI to select a file, the equivalent CLI command is added to your shell history. Press
↑to re-run it instantly. - Seamless workflow: Select interactively once, then repeat with up-arrow forever.
Note: Requires
jqto be installed.
👀 Watch Mode
Tired of Alt-Tab -> Up Arrow -> Enter? Use watch mode to re-run the request every time you save the file.
yapi watch ./my-request.yapi.yml
🔥 Load Testing
Stress test entire workflows with concurrent execution. Not just individual requests - stress test multi-step chains, auth flows, and complex scenarios. Perfect for finding bottlenecks in real-world usage patterns.
# Stress test an auth flow: login -> create post -> fetch results yapi stress auth-flow.yapi.yml -n 1000 -p 50 # Run a multi-step workflow for 30 seconds yapi stress my-workflow.yapi.yml -d 30s -p 10 # Load test against production yapi stress checkout-flow.yapi.yml -e prod -n 500 -p 25
Options:
-n, --num-requests- Total number of workflow executions (default: 100)-p, --parallel- Number of concurrent workflow executions (default: 1)-d, --duration- Run for a specific duration (e.g., 10s, 1m) - overrides num-requests-e, --env- Target a specific environment from yapi.config.yml-y, --yes- Skip confirmation prompt
Key advantage: Each parallel execution runs the entire chain - login, get token, make authenticated request, etc. This tests your API under realistic load, not just isolated endpoints.
🔄 CI/CD Integration (GitHub Actions)
Run your yapi tests automatically in GitHub Actions with service orchestration and health checks built-in.
name: Integration Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm install - name: Run Yapi Integration Tests uses: jamierpond/yapi/action@0.X.X # specify version, or use @main for latest with: # Start your service in the background start: npm run dev # Wait for it to be healthy wait-on: http://localhost:3000/health # Run your test suite command: yapi test ./tests -a
Features:
- Automatically installs yapi CLI
- Starts background services (web servers, APIs, databases)
- Waits for health checks before running tests
- Fails the workflow if tests fail
Multiple services example:
- uses: jamierpond/yapi/action@0.X.X # specify version, or use @main for latest with: start: | docker-compose up -d pnpm --filter api dev wait-on: | http://localhost:8080/health http://localhost:3000/ready command: yapi test ./integration -a
See the action documentation for more options.
🧠 Editor Integration (LSP)
Unlike other API clients, yapi ships with a full LSP implementation out of the box. No extensions to install, no separate tools to configure. Your editor becomes an intelligent API development environment.
What You Get
| Feature | Description |
|---|---|
| Real-time Validation | Errors and warnings as you type, with precise line/column positions. Catches issues before you hit run. |
| Intelligent Autocompletion | Context-aware suggestions for keys, HTTP methods, content types, and more. |
| Hover Info | Hover over ${VAR} to see environment variable status and (redacted) values. |
| Go to Definition | Jump to referenced chain steps and variables. |
Neovim (Native Plugin)
yapi was built with Neovim in mind. First-class support via lua/yapi_nvim:
-- lazy.nvim { dir = "~/path/to/yapi/lua/yapi_nvim", config = function() require("yapi_nvim").setup({ lsp = true, -- Enables the yapi Language Server pretty = true, -- Uses the TUI renderer in the popup }) end }
Commands:
:YapiRun- Execute the current buffer:YapiWatch- Open a split with live reload
VS Code / Any LSP-Compatible Editor
The LSP communicates over stdio and works with any editor that supports the Language Server Protocol. Point your editor's LSP client to yapi lsp and you're set.
🌍 Environment Management
Create a yapi.config.yml file in your project root to manage multiple environments:
yapi: v1 default_environment: local environments: local: url: http://localhost:8080 vars: API_KEY: local_test_key DEBUG: "true" staging: url: https://staging.api.example.com vars: API_KEY: ${STAGING_KEY} # From shell environment DEBUG: "false" prod: url: https://api.example.com vars: API_KEY: ${PROD_KEY} DEBUG: "false"
Then reference these variables in your request files:
yapi: v1 url: ${url}/users method: GET headers: Authorization: Bearer ${API_KEY} X-Debug: ${DEBUG}
Switch environments with the -e flag:
yapi run get-users.yapi.yml -e staging
Benefits:
- Keep all environment configs in one place
- Commit safe defaults, load secrets from shell env
- No request file duplication across environments
- Perfect for CI/CD pipelines with multiple deployment stages
📂 Project Structure
cmd/yapi: The main CLI entry point.internal/executor: The brains. HTTP, gRPC, TCP, and GraphQL logic.internal/tui: The BubbleTea-powered interactive UI.examples/: Look here for a ton of practical YAML examples!webapp/: The Next.js code for yapi.run.
🤝 Contributing
Found a bug? Want to add WebSocket support? PRs are welcome!
- Fork it.
make buildto ensure it compiles.make testto run the suite.- Ship it.
Made with ☕ and Go.