Skip to main content

CLI tool for API testing, load testing, and mock server generation

Project description

api-forge

CLI tool for API testing, load testing, and mock server generation.

PyPI version Python 3.9+ License: MIT


Why api-forge?

Testing APIs shouldn't require heavy frameworks or complex setup. api-forge is a lightweight CLI tool that provides:

  • Test Suites — Define API tests in simple YAML files
  • Assertions — Validate status codes, headers, JSON paths, response times
  • Variable Chaining — Extract values from responses for use in subsequent requests
  • Load Testing — Stress test endpoints with configurable concurrency
  • Mock Server — Spin up mock APIs from YAML for development/testing
  • Quick Requests — cURL-like commands with pretty output

Installation

pip install api-forge-cli

Quick Start

# Make a quick GET request
api-forge get https://jsonplaceholder.typicode.com/posts/1

# Run a test suite
api-forge test suite.yaml

# Load test an endpoint
api-forge load https://api.example.com/health -n 50 -d 10

# Start a mock server
api-forge mock mock.yaml

# Generate example configs
api-forge init --type test -o suite.yaml

Commands

get / post / put / delete — Quick Requests

# GET request
api-forge get https://api.example.com/users

# POST with JSON body
api-forge post https://api.example.com/users -d '{"name": "Alice"}'

# With custom headers
api-forge get https://api.example.com/users -H "Authorization:Bearer token"

# PUT request
api-forge put https://api.example.com/users/1 -d '{"name": "Bob"}'

# DELETE request
api-forge delete https://api.example.com/users/1

test — Run API Test Suites

api-forge test suite.yaml
api-forge test tests/api-tests.yaml -v

Test suites are defined in YAML:

name: "User API Tests"
base_url: "https://api.example.com"

headers:
  Authorization: "Bearer {{token}}"

variables:
  token: "your-api-token"

requests:
  - name: "Get all users"
    url: "/users"
    method: GET
    assertions:
      - type: status
        expected: 200
      - type: response_time
        expected: 2000

  - name: "Create user"
    url: "/users"
    method: POST
    body:
      name: "Alice"
      email: "alice@example.com"
    assertions:
      - type: status
        expected: 201
      - type: json_path
        path: "id"
        expected: 1
    variables:
      new_user_id: "id"  # Extract for next request

  - name: "Get created user"
    url: "/users/{{new_user_id}}"
    method: GET
    assertions:
      - type: status
        expected: 200

load — Load Testing

# Quick load test
api-forge load https://api.example.com/health -n 50 -d 30

# From config file
api-forge load -c loadtest.yaml
Option Description
-n, --concurrency Number of concurrent connections (default: 10)
-d, --duration Test duration in seconds (default: 10)
--rps Requests per second limit (0 = unlimited)
-c, --config Load test config YAML file

Load test config:

url: "https://api.example.com/users"
method: GET
concurrency: 100
duration_seconds: 60
requests_per_second: 500
timeout: 10.0
headers:
  Authorization: "Bearer token"

Output includes:

  • Total requests, success/failure counts
  • Requests per second achieved
  • Latency percentiles (min, avg, p50, p95, p99, max)
  • Status code distribution
  • Error samples

mock — Mock Server

# Start mock server from config
api-forge mock mock.yaml

# Custom port
api-forge mock mock.yaml -p 3000

# Default server (returns 404 for all)
api-forge mock

Mock server config:

name: "Test API"
port: 8000
cors: true

endpoints:
  - path: "/health"
    method: GET
    status: 200
    body:
      status: "healthy"

  - path: "/users"
    method: GET
    status: 200
    headers:
      X-Total-Count: "100"
    body:
      - id: 1
        name: "Alice"
      - id: 2
        name: "Bob"

  - path: "/users"
    method: POST
    status: 201
    body:
      id: 3
      message: "Created"

  - path: "/slow"
    method: GET
    status: 200
    delay_ms: 2000  # Simulate latency
    body:
      message: "Slow response"

  - path: "/users/*"  # Wildcard matching
    method: GET
    status: 200
    body:
      id: 1
      name: "User"

init — Generate Examples

api-forge init --type test -o suite.yaml
api-forge init --type load -o loadtest.yaml
api-forge init --type mock -o mock.yaml

Assertion Types

Type Description Example
status HTTP status code expected: 200 or expected: [200, 201]
header Header value contains header: Content-Type, expected: json
body_contains Body contains string expected: "success"
json_path JSON path equals value path: user.id, expected: 123
body_regex Body matches regex expected: "\\d{5}"
response_time Max response time (ms) expected: 500

Variable Substitution

Use {{variable_name}} syntax in URLs, headers, and body:

variables:
  api_key: "secret123"
  user_id: "456"

requests:
  - name: "Get user"
    url: "/users/{{user_id}}"
    headers:
      X-API-Key: "{{api_key}}"

Extract variables from responses for request chaining:

requests:
  - name: "Login"
    url: "/auth/login"
    method: POST
    body:
      username: "admin"
      password: "secret"
    variables:
      auth_token: "token"  # Extract $.token from response

  - name: "Protected endpoint"
    url: "/protected"
    headers:
      Authorization: "Bearer {{auth_token}}"

Examples

Full Test Suite with Chaining

name: "E-commerce API"
base_url: "https://api.shop.example.com"

requests:
  - name: "Create product"
    url: "/products"
    method: POST
    body:
      name: "Widget"
      price: 29.99
    assertions:
      - type: status
        expected: 201
    variables:
      product_id: "id"

  - name: "Get product"
    url: "/products/{{product_id}}"
    assertions:
      - type: json_path
        path: "name"
        expected: "Widget"

  - name: "Delete product"
    url: "/products/{{product_id}}"
    method: DELETE
    assertions:
      - type: status
        expected: 204

Load Test with Detailed Config

url: "https://api.example.com/search"
method: POST
concurrency: 200
duration_seconds: 120
requests_per_second: 1000
timeout: 5.0
headers:
  Content-Type: "application/json"
body:
  query: "test"
  limit: 10

Development

git clone https://github.com/SanjaySundarMurthy/api-forge.git
cd api-forge
pip install -e ".[dev]"
pytest tests/ -v

Author

Sanjay Sundar Murthy


License

MIT License — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

api_forge_cli-1.0.0.tar.gz (21.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

api_forge_cli-1.0.0-py3-none-any.whl (18.5 kB view details)

Uploaded Python 3

File details

Details for the file api_forge_cli-1.0.0.tar.gz.

File metadata

  • Download URL: api_forge_cli-1.0.0.tar.gz
  • Upload date:
  • Size: 21.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for api_forge_cli-1.0.0.tar.gz
Algorithm Hash digest
SHA256 bdcbb4966892fffff448e50d9b2a1bd067b33f9675cee9bb88e96cf2cac54e64
MD5 02e101c73ec0927d2f762dbcf2f1e05a
BLAKE2b-256 88eda2a2ec63037fb8340299a61178407f1bebf05edf5a5c385e9b9c34e0fd93

See more details on using hashes here.

File details

Details for the file api_forge_cli-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: api_forge_cli-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 18.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.7

File hashes

Hashes for api_forge_cli-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0e2daf870ec540a65a3338020917dc7c6b69b3bc10a23841f80e0ac1dd80f254
MD5 4d352f6bc5706964bb48ee61907f9c16
BLAKE2b-256 770ccb73e5458f46d61fefe9139c47a355415d58339f0497d9419fdc49cdad68

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page