apter
A blazingly fast, simple, and powerful CLI for API testing. Written in Go.
apter is a modern command-line tool designed for the "tests-as-code" workflow. Write your API tests in simple, declarative JSON files, check them into Git, and run them lightning-fast in your terminal or CI/CD pipelines.
β¨ Features
- Declarative JSON Suites: Simple, human-readable test definitions. No complex scripting needed for most cases.
- Powerful Request Chaining: Use
capture and dependsOn to create complex user workflows (e.g., login -> create resource -> fetch resource).
- Data-Driven Testing: Run a single test template against hundreds of rows from a CSV file.
- Flexible Assertions: Validate status codes, headers, response times, and body content using simple key-value pairs or full JSON Schema.
- Built-in Auth Helpers: Handles Bearer Token and Basic Auth automatically.
- Cookies & Sessions: Automatic cookie jar for testing stateful APIs that require sessions.
- File Uploads: First-class support for
multipart/form-data requests.
- GraphQL Support: A dedicated
graphql block makes testing GraphQL APIs simple and intuitive.
- Test Hooks: Use
setup and teardown requests to prepare and clean up your test environment.
- CI/CD Ready: Generate JUnit XML reports for seamless integration with Jenkins, GitLab CI, GitHub Actions, and more.
- Zero Dependencies: Distributed as a single, static binary. It just works.
π Demo
(This is an example of what the tool's output looks like)
$ apter -dir ./suites -env reqres -v
Starting API tests using environment: reqres (https://reqres.in)
Running suite: rest_playground.json (3 tests)
========================================
[15:30:01] Login and Capture Token (155ms) PASS
>>>>>>>>>>>>>>>>>>>>>>>>> REQUEST >>>>>>>>>>>>>>>>>>>>>>>>>
POST https://reqres.in/api/login
Content-Type: application/json
User-Agent: Go-http-client/1.1
{
"email": "[email protected]",
"password": "cityslicka"
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<< RESPONSE <<<<<<<<<<<<<<<<<<<<<<<<<
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Fri, 20 Oct 2023 14:30:01 GMT
{
"token": "QpwL5tke4Pnpja7X4"
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
[15:30:02] Get Protected User List (210ms) PASS
[15:30:02] Create a New User (180ms) PASS
All tests passed!
π€ Why Apter?
apter is designed to be a fast, simple, and git-friendly alternative to heavier tools.
| Feature |
apter |
newman (Postman CLI) |
Bruno CLI |
| Configuration Format |
Simple, clean JSON. Very easy to learn. |
Postman Collection JSON. Verbose, not human-friendly. |
Bru Lang. Simple, text-based markup. |
| Ease of Use |
β
Easiest for declarative tests. |
Moderate. Requires Postman ecosystem. |
Easy. Intuitive markup language. |
| Dependencies |
β
None. Single static binary. |
Requires Node.js and npm/yarn. |
Requires Node.js and npm/yarn. |
| Performance |
β
Fastest. Native Go execution. |
Slower. Node.js startup overhead. |
Slower. Node.js startup overhead. |
| Git Workflow |
β
Excellent. Built for "tests-as-code". |
Poor. JSON is hard to diff. |
β
Excellent. Also built for "tests-as-code". |
| Scripting |
No. Fully declarative. |
β
Yes. Full JavaScript engine. |
β
Yes. Full JavaScript engine. |
Verdict: For teams who value speed, portability, and a "tests-as-code" philosophy, apter provides the simplest and fastest path to robust API testing.
π¦ Installation
With Go
go install github.com/muntader/apter/cmd/apter@latest
From Binaries
Download the pre-compiled binary for your OS from the GitHub Releases page.
β‘ Quick Start
-
Create a configuration file config.json:
{
"environments": {
"production": {
"baseUrl": "https://api.myapp.com"
},
"reqres": {
"baseUrl": "https://reqres.in"
}
}
}
-
Create your first test file suites/smoke_test.json:
{
"requests": [
{
"name": "Get a list of users",
"method": "GET",
"endpoint": "/api/users?page=2",
"expected": {
"statusCode": 200,
"bodyContains": {
"page": 2
}
}
}
]
}
-
Run it!
apter -file suites/smoke_test.json -env reqres
π Core Concepts
1. Assertions (expected)
Validate responses with a simple status code or a rich object.
"expected": 200
or
"expected": {
"statusCode": 201,
"maxLatencyMs": 500,
"headers": {
"Content-Type": "application/json; charset=utf-8"
},
"bodyContains": {
"job": "leader",
"id": "{{created_user_id}}"
}
}
2. Variables & Chaining (capture & dependsOn)
Capture a value from one response and use it in another.
[
{
"name": "Login",
"method": "POST",
"endpoint": "/api/login",
"payload": { "email": "[email protected]", "password": "..." },
"capture": {
"auth_token": "token"
},
"expected": 200
},
{
"name": "Get Profile",
"method": "GET",
"endpoint": "/api/users/2",
"dependsOn": "Login",
"headers": {
"Authorization": "Token {{auth_token}}"
},
"expected": 200
}
]
3. Authentication (auth)
Let apter handle Authorization headers for you.
"auth": {
"type": "bearer",
"token": "{{auth_token}}"
}
or
"auth": {
"type": "basic",
"username": "admin",
"password": "{{admin_password}}"
}
Test multipart/form-data endpoints by prefixing file paths with @.
{
"name": "Upload Avatar",
"method": "POST",
"endpoint": "/upload",
"bodyType": "form-data",
"formData": {
"file": "@./path/to/my_avatar.png",
"user_id": "123"
},
"expected": 200
}
5. GraphQL
Use the dedicated graphql block for GraphQL APIs. apter will construct the correct request body.
{
"name": "Get Character",
"endpoint": "/graphql",
"graphql": {
"query": "query GetCharacter($id: ID!) { character(id: $id) { name status } }",
"variables": {
"id": "1"
}
},
"expected": 200
}
6. Test Hooks (setup & teardown)
Run a request once before all tests in a suite, and another once all tests are finished.
{
"setup": "Create Admin Token",
"teardown": "Delete Created Resource",
"requests": [
{ "name": "Create Admin Token", "...": "..." },
{ "name": "Test Case 1", "...": "..." },
{ "name": "Test Case 2", "...": "..." },
{ "name": "Delete Created Resource", "...": "..." }
]
}
7. Data-Driven Testing (dataFile)
Run one test case against many rows of data from a CSV file.
data/users.csv
name,job,expectedStatus
Morpheus,Leader,201
Neo,The One,201
suites/data_test.json
{
"requests": [
{
"name": "Create User from Data File",
"method": "POST",
"endpoint": "/api/users",
"dataFile": "data/users.csv",
"payload": {
"name": "{{name}}",
"job": "{{job}}"
},
"expected": {
"statusCode": "{{expectedStatus}}"
}
}
]
}
βοΈ CLI Reference
| Flag |
Shorthand |
Description |
Example |
--dir |
|
Run all test suites (*.json) in a directory. |
-dir ./suites |
--file |
|
Run a single test suite file. |
-file ./suites/auth.json |
--name |
|
Run a single named test from a file (requires -file). |
-file ./s.json -name "Login" |
--config |
|
Path to the configuration file. |
-config ./prod.config.json |
--env |
|
Environment to use from the config file. |
-env production |
--var |
|
Set a variable (key=value). Use multiple times. |
--var "user=admin" --var "pass=secret" |
--reporter |
|
Reporter to use (console, junit). |
-reporter junit |
--output |
|
Output file for reporters (e.g., junit). |
-output report.xml |
--verbose |
-v |
Enable verbose request/response logging. |
-v |
--insecure |
-k |
Skip TLS certificate verification. |
-k |
π€ Contributing
Contributions, issues, and feature requests are welcome! Feel free to check the issues page.
π License
This project is MIT licensed.