API testing CLIs overview
Overview
This workspace ships five Rust API testing CLIs (api-rest, api-gql, api-grpc, api-websocket, api-test) plus the shared library
crate api-testing-core. The canonical Rust CLI contracts are the source of truth: flags, defaults, exit codes, and on-disk artifacts
(history files, reports, results).
Detailed command specs live with each binary:
crates/api-rest/README.mdcrates/api-gql/README.mdcrates/api-grpc/README.mdcrates/api-websocket/README.mdcrates/api-test/README.md
This README focuses on the shared repository layout, cross-CLI concepts, and the api-testing-core surface area.
Binaries and command surface mapping
api-rest(REST)api-rest call(default)api-rest historyapi-rest report
api-gql(GraphQL)api-gql call(default)api-gql historyapi-gql reportapi-gql schema
api-test(suite runner)api-test runapi-test summary
api-grpc(gRPC unary)api-grpc call(default)api-grpc historyapi-grpc reportapi-grpc report-from-cmd
api-websocket(WebSocket scripted sessions)api-websocket call(default)api-websocket historyapi-websocket reportapi-websocket report-from-cmd
Notes:
api-testexecutes REST/GraphQL/gRPC/WebSocket cases through shared core runners (no shelling out to scripts or the binaries).api-rest/api-gql/api-grpc/api-websocketalso providereport-from-cmdas a Rust-only convenience for replaying savedcallsnippets.
api-testing-core scope
api-testing-core is a library crate used by all five CLIs. Key modules:
config: setup dir discovery for REST/GraphQL/gRPC/WebSocket configs.env_file:.envparsing + key normalization helpers.cli_*: shared CLI helpers (endpoint resolution, history I/O, report args, CLI utilities).history,report,markdown,redact,cmd_snippet: shared report/history rendering and snippet parsing.rest: request schema, runner, expect/cleanup logic, report rendering.graphql: schema/vars loading, auth/JWT resolution, runner, expect/allow-errors, report rendering, mutation detection.grpc: unary request schema, transport runner, expect logic, report rendering.websocket: request schema, scripted runner, expect logic, report rendering.suite: suite schema v1, path resolution, filters, safety gates, auth integration, runner, cleanup, results, summary, JUnit (includingtype: websocket).
Transport decision and reuse matrix
- Transport decision:
- gRPC selected:
grpcurladapter for unary MVP (api-testing-core::grpc::runner). - gRPC rejected for MVP: native dynamic invocation path (higher complexity for the same unary delivery goal).
- WebSocket selected: native Rust
tungstenitetransport (api-testing-core::websocket::runner). - WebSocket rejected for MVP: external adapter shell-out (
websocat-style).
- gRPC selected:
- Reuse matrix:
- unchanged: suite selection/filtering, run directory/artifact envelope, summary/JUnit/results rendering.
- additive grpc: suite schema defaults/case validation,
type: grpcrunner branch, gRPC endpoint/token resolution. - additive websocket: suite schema defaults/case validation,
type: websocketrunner branch, WS endpoint/token resolution.
- Evidence commands:
cargo test -p nils-api-testing-core --test suite_rest_graphql_matrixcargo test -p nils-api-testing-core --test suite_runner_loopbackcargo test -p nils-api-testing-core --test suite_runner_grpc_matrixcargo test -p nils-api-testing-core --test suite_runner_websocket_matrixcargo test -p nils-api-test suite_schema
Shared terminology
- Setup dir
- Protocol-specific config directory.
- Canonical locations: REST
setup/rest, GraphQLsetup/graphql, gRPCsetup/grpc, WebSocketsetup/websocket.
- Config dir
- CLI arg
--config-dir <dir>that seeds setup-dir discovery. - Discovery searches upward for known config files; fallback uses the canonical
setup/<tool>when applicable.
- CLI arg
- Env preset
--env <name>selects a base URL fromendpoints.env(+ optional.localoverrides).- REST:
REST_URL_<ENV_KEY>; GraphQL:GQL_URL_<ENV_KEY>; gRPC:GRPC_URL_<ENV_KEY>. - WebSocket:
WS_URL_<ENV_KEY>. - If the value looks like
http(s)://...orws(s)://..., it is treated as a direct URL (like--url).
- Token/JWT profile
- REST:
--token <name>orREST_TOKEN_NAMEselectsREST_TOKEN_<NAME>. - GraphQL:
--jwt <name>orGQL_JWT_NAMEselectsGQL_JWT_<NAME>. - gRPC:
--token <name>orGRPC_TOKEN_NAMEselectsGRPC_TOKEN_<NAME>. - WebSocket:
--token <name>orWS_TOKEN_NAMEselectsWS_TOKEN_<NAME>. - REST fallback:
ACCESS_TOKEN, thenSERVICE_TOKENif no profile is selected. - GraphQL fallback:
ACCESS_TOKEN, thenSERVICE_TOKENif no profile is selected.
- REST:
- History
- REST:
<setup_dir>/.rest_history, GraphQL:<setup_dir>/.gql_history, gRPC:<setup_dir>/.grpc_history, WebSocket:<setup_dir>/.ws_history. - Enabled by default, can be disabled, and supports rotation/size limits.
- REST:
- Report
- Markdown artifact (usually under
<repo>/docs/) capturing request/operation, response, and optional assertions. - Redacts common secret fields by default, with opt-out flags for debugging.
- Markdown artifact (usually under
- Suite
- JSON manifest (
version: 1) that drivesapi-test runand defines cases, defaults, auth, and cleanup.
- JSON manifest (
Canonical repo layouts
The CLIs support the following repository layouts.
Layout A: App repo with setup/ + tests/ (recommended)
<repo>/
setup/
rest/
endpoints.env
endpoints.local.env # optional (local override)
tokens.env
tokens.local.env # optional (local tokens; do not commit)
graphql/
endpoints.env
endpoints.local.env # optional (local override)
jwts.env
jwts.local.env # optional (local tokens; do not commit)
schema.env # optional (sets GQL_SCHEMA_FILE)
schema.local.env # optional (local override)
schema.graphql # or: schema.gql / schema.graphqls / api.graphql / api.gql
operations/ # optional (login.graphql, shared ops, etc.)
grpc/
endpoints.env
endpoints.local.env # optional (local override)
tokens.env
tokens.local.env # optional (local tokens; do not commit)
requests/ # *.grpc.json request definitions
websocket/
endpoints.env
endpoints.local.env # optional (local override)
tokens.env
tokens.local.env # optional (local tokens; do not commit)
requests/ # *.ws.json or *.websocket.json request definitions
tests/
api/
suites/
<name>.suite.json
out/
api-test-runner/ # suite runner output base dir
Layout B: Suites under setup/ (fallback)
api-test resolves --suite <name> to:
<repo>/tests/api/suites/<name>.suite.json(preferred)<repo>/setup/api/suites/<name>.suite.json(fallback)
Layout C: Custom suites directory
API_TEST_SUITES_DIR=<path>overrides the suites directory for--suite <name>.
Quickstart examples
api-rest
Run a request:
Write a report:
Generate a report from a saved snippet:
|
api-gql
Run an operation:
Write a report:
Resolve and print schema:
api-grpc
Run a unary request:
Write a report:
Generate a report from a saved snippet:
|
api-test
Run a suite (always emits results JSON to stdout):
Use an explicit suite file:
Write results JSON + JUnit:
Render a Markdown summary:
api-websocket
Run a scripted request:
Write a report:
Generate a report from a saved snippet:
|
Suite runner behavior (high-level)
- Results JSON is always emitted to stdout.
--outwrites an additional copy. - Output directory base defaults to
<repo>/out/api-test-runner(override viaAPI_TEST_OUTPUT_DIR). - Each run creates
<output_dir>/<run_id>/whererun_idisYYYYMMDD-HHMMSSZ. - Per-case artifacts include
<case>.response.jsonand<case>.stderr.log, referenced in results JSON. - Exit code is
2when any case fails; otherwise0. - Write safety is two-step:
- Case must set
allowWrite: true. - Writes must be enabled via
--allow-writes,API_TEST_ALLOW_WRITES_ENABLED=true, orenv: local.
- Case must set
- Optional suite auth can derive tokens from secret JSON in
API_TEST_AUTH_JSON. - Optional cleanup steps run after the main case; cleanup failures mark the case failed.
Suite runner environment variables
API_TEST_OUTPUT_DIR: override the base output directory.API_TEST_SUITES_DIR: override the suites directory used by--suite.API_TEST_ALLOW_WRITES_ENABLED: enable write-capable cases.API_TEST_REST_URL: override REST base URL for all REST/rest-flow cases.API_TEST_GQL_URL: override GraphQL endpoint URL for all GraphQL cases.API_TEST_GRPC_URL: override gRPC target for all gRPC cases.API_TEST_WS_URL: override WebSocket target URL for all websocket cases.API_TEST_AUTH_JSON: credentials JSON used by suite auth (default key name).GITHUB_STEP_SUMMARY: when set,api-test summaryappends Markdown output (disable via--no-github-summary).