Project · Aug 29, 2026
Gherkio: Declarative API Testing in Go
A Go CLI for describing API workflows in YAML, checking HTTP and Redis state, mocking outbound requests, and generating reports without test glue code.
Why I built it
Before building Gherkio, I used kulala.nvim for day-to-day API testing inside Neovim. It worked well for sending requests, but its assertion features covered only a small part of what I needed, so I still had to verify many responses and side effects manually. Some cases also required checking whether the application wrote the expected Redis key, waiting for an asynchronous process, or carrying an ID through several requests.
I wanted those checks to live in one readable workflow without turning every test into another Go or JavaScript program. Gherkio became a Go CLI with a YAML DSL for requests, assertions, saved values, reusable scenarios, retries, and read-only Redis checks.
The CLI is distributed as a single binary. It does not require a language runtime or a separate mock proxy, although live tests still depend on the API and datastore being tested.
Why a DSL
The DSL describes what a workflow should do: send a request, check the response, save a value, and use that value later. Setup and teardown use the same step model, and a shared scenario can be included with use: instead of copying authentication or lookup requests between files.
scenario: Create and verify a user
steps:
- name: Register user
request:
method: POST
url: /v1/users
body:
email: $randomEmail
expect:
status: 201
body.data.id: exists
save:
USER_ID: body.data.id
- name: Fetch created user
request:
method: GET
url: /v1/users/$USER_ID
expect:
status: 200
body.data.id: "$USER_ID"
The constraint is deliberate: a Gherkio file cannot run arbitrary application code. When a workflow needs custom behavior, I prefer adding a small, named DSL capability rather than embedding a scripting language.
HTTP and Redis in one workflow
One reason I added Redis support was to test behavior that an HTTP assertion cannot prove on its own. An endpoint may return quickly while reading from the database, or return the correct data without populating its cache.
Redis connections are configured in the selected environment. Scenario steps can only use get, exists, ttl, and hgetall; write commands, key scans, and arbitrary scripts are intentionally unavailable.
steps:
- name: Fetch product
request:
method: GET
url: /v1/products/42
expect:
status: 200
body.data.id: exists
save:
PRODUCT_ID: body.data.id
- name: Wait for cached product
redis:
connection: application-cache
command: get
key: "product:$PRODUCT_ID"
expect:
redis.exists: true
redis.value.id: "$PRODUCT_ID"
retry:
attempts: 10
interval: 200
backoff: constant
- name: Check cache lifetime
redis:
connection: application-cache
command: ttl
key: "product:$PRODUCT_ID"
expect:
redis.ttl: gt 0
The scenario syntax stays the same for Redis Sentinel. Direct addresses, Sentinel discovery, authentication, TLS, database selection, and timeouts belong to the environment file.
Deterministic tests and asynchronous workflows
Gherkio can intercept matching outbound HTTP requests before network dispatch. Mock rules live in an environment file and can reflect request body, header, or query values into the response. I use this for third-party APIs and for the repository's executable examples, which can run without a real backend.
Retries handle one request that may eventually succeed. For workflows that need to perform several actions again, such as selecting an unused item and refetching a list, a bounded repeat block runs nested steps until its condition is true or its attempt limit is reached. The attempt limit is mandatory so a test cannot loop forever.
Regular test runs and virtual-user load runs use the same scenario files. Load execution gives each virtual user a private variable store and runs that user's iterations sequentially. It is useful for repeating complete API workflows and producing one report, but it is not intended to replace a specialized performance tool such as k6.
MCP and reporting
The MCP server exposes Gherkio's project structure and test operations to compatible coding assistants. It can convert cURL commands, inspect the DSL, validate YAML, create scenarios, and run an individual step or complete workflow.
I do not treat the agent as an unattended test author. The intended flow is to establish the expected payload and assertions, show the proposed variants, validate the scenario, perform a dry run, and ask for confirmation before writing or executing it.
Every run produces a terminal summary and can generate HTML or JSON reports. Reports include composed steps, repeat attempts, assertions, timing, masked requests, and the variables available before and after execution. Failed runs can also write a debug snapshot for reproduction.
Current boundaries
Gherkio is most useful for API integration workflows that benefit from readable, version-controlled scenarios. Its boundaries are intentional:
- Redis access is read-only.
- HTTP mocks do not emulate Redis or other datastore protocols.
- Repeat blocks are bounded and cannot become general recursion.
- The load runner repeats workflows with isolated virtual users, but does not provide k6's traffic models or performance analysis.
- More specialized behavior requires extending the DSL or using another test tool.
The core is written in Go 1.25 and uses YAML plus generated JSON Schema for the DSL. Redis communication uses a small built-in RESP client with standalone and Sentinel support. Documentation is built with mdBook.
Technical Challenges & Solutions
Keeping composed workflows predictable
Values saved by a shared scenario are returned to its caller, while temporary values passed through with: are restored afterward. This makes authentication and lookup workflows reusable without leaking their input overrides.
Checking cache state without turning the DSL into a Redis console
Added a small RESP client with direct and Sentinel discovery, but limited scenario commands to read-only GET, EXISTS, TTL, and HGETALL operations.
Giving coding assistants useful access without removing human control
Exposed planning, conversion, validation, and execution through MCP. The intended flow validates and dry-runs a scenario, then asks for confirmation before writing or running it.
Under the hood
Key technical highlights
- Reusable YAML workflows with setup, teardown, composition, saved values, conditions, retries, and bounded repeat blocks
- Read-only checks for Redis strings, hashes, key existence, and TTL through standalone or Sentinel connections
- In-process HTTP mocks for deterministic tests without running a separate mock server
- HTML and JSON reports for regular runs and virtual-user load executions
- An MCP server that helps coding assistants plan, validate, and run tests with an explicit confirmation step