Step CI Cheat Sheet
Overview
Step CI is an open-source API testing and monitoring framework that uses declarative YAML workflows to define API tests. It supports REST, GraphQL, gRPC, tRPC, and SOAP APIs, with built-in assertions, data capture, performance testing, and CI/CD integration. Step CI focuses on simplicity, requiring no code to write comprehensive API test suites.
Step CI provides features like environment variables, reusable components, request chaining with captured values, schema validation, load testing, and multiple output formats. It can run locally, in CI/CD pipelines, or as a monitoring solution, making it versatile for API quality assurance workflows.
Installation
# npm (global)
npm install -g stepci
# npx (no install)
npx stepci run workflow.yml
# Docker
docker run ghcr.io/stepci/stepci run workflow.yml
# Homebrew
brew install stepci
# Verify installation
stepci --version
Core Commands
| Command | Description |
|---|---|
stepci run workflow.yml | Run a workflow file |
stepci run workflow.yml --env env.yml | Run with environment file |
stepci run workflow.yml --secret key=val | Pass secrets |
stepci run workflow.yml -l | Load test mode |
stepci generate URL | Generate workflow from OpenAPI spec |
stepci init | Create a starter workflow |
Basic Workflow
# workflow.yml
version: "1.1"
name: API Tests
env:
host: https://api.example.com
token: Bearer mytoken
tests:
health:
steps:
- name: Health check
http:
url: ${{env.host}}/health
method: GET
check:
status: 200
jsonpath:
$.status: ok
users:
steps:
- name: List users
http:
url: ${{env.host}}/users
method: GET
headers:
Authorization: ${{env.token}}
check:
status: 200
jsonpath:
$.data:
- isArray: true
headers:
Content-Type: application/json
Request Types
GET Request
steps:
- name: Get user
http:
url: https://api.example.com/users/123
method: GET
headers:
Accept: application/json
Authorization: Bearer token123
check:
status: 200
POST Request with JSON
steps:
- name: Create user
http:
url: https://api.example.com/users
method: POST
headers:
Content-Type: application/json
json:
name: John Doe
email: john@example.com
role: admin
check:
status: 201
jsonpath:
$.id:
- isNumber: true
PUT and DELETE
steps:
- name: Update user
http:
url: https://api.example.com/users/123
method: PUT
headers:
Content-Type: application/json
json:
name: Jane Doe
check:
status: 200
- name: Delete user
http:
url: https://api.example.com/users/123
method: DELETE
check:
status: 204
Form Data and File Upload
steps:
- name: Upload file
http:
url: https://api.example.com/upload
method: POST
formData:
file:
file: ./avatar.png
description: Profile photo
check:
status: 200
Assertions (Checks)
steps:
- name: Comprehensive assertions
http:
url: https://api.example.com/users/123
method: GET
check:
# Status code
status: 200
# Response time
performance:
total:
- lte: 500
# Headers
headers:
Content-Type: application/json
Cache-Control:
- contains: no-cache
# JSON body assertions
jsonpath:
$.id:
- eq: 123
$.name:
- eq: "John Doe"
$.email:
- matches: "^[\\w.]+@[\\w.]+$"
$.active:
- eq: true
$.roles:
- isArray: true
- length: 3
$.balance:
- gte: 0
- lte: 10000
$.created_at:
- isString: true
# Body content checks
body:
- contains: John
- notContains: error
# Schema validation
schema:
type: object
required: [id, name, email]
properties:
id:
type: integer
name:
type: string
email:
type: string
format: email
Capturing Values
tests:
auth_flow:
steps:
- name: Login
http:
url: ${{env.host}}/auth/login
method: POST
json:
username: admin
password: secret
check:
status: 200
captures:
auth_token:
jsonpath: $.token
user_id:
jsonpath: $.user.id
- name: Get profile
http:
url: ${{env.host}}/users/${{captures.user_id}}
method: GET
headers:
Authorization: Bearer ${{captures.auth_token}}
check:
status: 200
jsonpath:
$.id:
- eq: ${{captures.user_id}}
GraphQL Testing
steps:
- name: GraphQL query
http:
url: https://api.example.com/graphql
method: POST
graphql:
query: |
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
variables:
id: "123"
check:
status: 200
jsonpath:
$.data.user.name: "John Doe"
Load Testing
version: "1.1"
name: Load Test
env:
host: https://api.example.com
tests:
load:
steps:
- name: Health endpoint load
http:
url: ${{env.host}}/health
method: GET
check:
status: 200
performance:
total:
- lte: 200
# Run with load testing enabled
stepci run workflow.yml -l --concurrency 50 --duration 60s
# Custom load profile
stepci run workflow.yml -l --concurrency 100 --iterations 10000
Environment Configuration
# env.yml
host: https://api.example.com
token: Bearer production-token
admin_email: admin@example.com
# Run with environment file
stepci run workflow.yml --env env.yml
# Override with secrets
stepci run workflow.yml --env env.yml --secret token="Bearer new-token"
Advanced Usage
Conditional Steps
steps:
- name: Create user
http:
url: ${{env.host}}/users
method: POST
json:
name: Test User
check:
status: 201
captures:
user_id:
jsonpath: $.id
if: ${{env.create_user}} == "true"
Reusable Components
version: "1.1"
name: API Tests
components:
headers:
auth:
Authorization: Bearer ${{env.token}}
Accept: application/json
tests:
users:
steps:
- name: List users
http:
url: ${{env.host}}/users
method: GET
headers:
$ref: "#/components/headers/auth"
check:
status: 200
CI/CD Integration
# GitHub Actions
name: API Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm install -g stepci
- run: stepci run workflow.yml --env env.ci.yml
Generate from OpenAPI
# Generate test workflow from OpenAPI spec
stepci generate https://api.example.com/openapi.json > workflow.yml
# From local file
stepci generate ./openapi.yaml > workflow.yml
Troubleshooting
| Issue | Solution |
|---|---|
| Variable not resolved | Check syntax: ${{env.name}} for env, ${{captures.name}} for captures |
| SSL error | Use --no-tls-verify for self-signed certificates |
| Timeout | Increase request timeout in workflow options |
| JSONPath not matching | Verify path using a JSONPath evaluator; check response body |
| Schema validation fails | Ensure JSON Schema draft version is compatible |
| Load test OOM | Reduce concurrency; increase system limits |
| Captures empty | Ensure the preceding step succeeds before using captured values |
| GraphQL errors | Verify query syntax; check variables match schema |