API Testing Example
Learn how to use HTTPTests to test a REST API with full CRUD operations, status code validation, and response header verification.
Overview
This example demonstrates testing a REST API that provides:
- Health check endpoint
- User management (GET, POST, PUT, DELETE)
- Product listing
- JSON response validation
- HTTP status code validation
Use Case
Perfect for:
- REST API testing
- Backend service validation
- API contract testing
- Regression testing after API changes
- CI/CD integration for API projects
API Endpoints
| Method | Path | Description | Expected Status |
|---|---|---|---|
| GET | /health | Health check | 200 |
| GET | /api/users | List all users | 200 |
| GET | /api/users/123 | Get specific user | 200 |
| POST | /api/users | Create new user | 201 |
| PUT | /api/users/123 | Update user | 200 |
| DELETE | /api/users/123 | Delete user | 204 |
| GET | /api/products | List products | 200 |
File Structure
api-testing/
├── Dockerfile
├── nginx.conf
└── .httptests/
├── config.yml
└── test.jsonConfiguration Files
Dockerfile
FROM nginx:alpine
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Simple Nginx container that serves our API.
nginx.conf
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name _;
# Health check endpoint
location = /health {
default_type application/json;
return 200 '{"status": "healthy", "timestamp": "2025-01-01T00:00:00Z"}';
}
# Get all users
location = /api/users {
default_type application/json;
if ($request_method = GET) {
return 200 '{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}';
}
if ($request_method = POST) {
return 201 '{"id": 3, "name": "Charlie", "created": true}';
}
return 405;
}
# Get specific user
location ~ ^/api/users/(\d+)$ {
default_type application/json;
if ($request_method = GET) {
return 200 '{"id": $1, "name": "User $1", "email": "user$1@example.com"}';
}
if ($request_method = PUT) {
return 200 '{"id": $1, "name": "Updated User", "updated": true}';
}
if ($request_method = DELETE) {
return 204;
}
return 405;
}
# Get products
location = /api/products {
default_type application/json;
return 200 '{"products": [{"id": 1, "name": "Widget", "price": 19.99}]}';
}
# Default - not found
location / {
default_type application/json;
return 404 '{"error": "Not found"}';
}
}
}This configuration:
- Returns JSON responses directly from Nginx (mocking an API)
- Handles different HTTP methods
- Returns appropriate status codes
- Sets correct Content-Type headers
.httptests/config.yml
mock:
network_aliases:
- backend
nginx:
environment:
API_VERSION: v1Simple configuration:
- Creates a mock service (not used in this example, but available)
- Sets an environment variable for the API
.httptests/test.json
{
"hosts": {
"api.example.com": [
{
"paths": ["/health"],
"method": "GET",
"expectedStatus": 200,
"expectedResponseHeaders": [
["Content-Type", "application/json"]
]
},
{
"paths": ["/api/users"],
"method": "GET",
"expectedStatus": 200,
"expectedResponseHeaders": [
["Content-Type", "application/json"]
]
},
{
"paths": ["/api/users/123"],
"method": "GET",
"expectedStatus": 200,
"expectedResponseHeaders": [
["Content-Type", "application/json"]
]
},
{
"paths": ["/api/users"],
"method": "POST",
"expectedStatus": 201,
"expectedResponseHeaders": [
["Content-Type", "application/json"]
]
},
{
"paths": ["/api/users/456"],
"method": "PUT",
"expectedStatus": 200,
"expectedResponseHeaders": [
["Content-Type", "application/json"]
]
},
{
"paths": ["/api/users/789"],
"method": "DELETE",
"expectedStatus": 204
},
{
"paths": ["/api/products"],
"method": "GET",
"expectedStatus": 200,
"expectedResponseHeaders": [
["Content-Type", "application/json"]
]
}
]
}
}This test suite validates:
- ✅ All HTTP methods (GET, POST, PUT, DELETE)
- ✅ Different status codes (200, 201, 204)
- ✅ Response Content-Type headers
- ✅ Specific path parameters
GitHub Actions Workflow
Add this to .github/workflows/test.yml:
name: API Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: serviceguards-com/httptests-action@v2
with:
httptests-directory: ./api-testingExpected Test Output
🔧 Adding X-Upstream-Target headers to nginx configs...
🚀 Starting environment...
🧪 Running tests for httptests-api-testing
test_endpoints (__main__.IntegrationTests.test_endpoints) ... ok
→ Testing: GET api.example.com/health
✓ Status code: 200 (expected 200)
✓ Response header: content-type = application/json
→ Testing: GET api.example.com/api/users
✓ Status code: 200 (expected 200)
✓ Response header: content-type = application/json
→ Testing: GET api.example.com/api/users/123
✓ Status code: 200 (expected 200)
✓ Response header: content-type = application/json
→ Testing: POST api.example.com/api/users
✓ Status code: 201 (expected 201)
✓ Response header: content-type = application/json
→ Testing: PUT api.example.com/api/users/456
✓ Status code: 200 (expected 200)
✓ Response header: content-type = application/json
→ Testing: DELETE api.example.com/api/users/789
✓ Status code: 204 (expected 204)
→ Testing: GET api.example.com/api/products
✓ Status code: 200 (expected 200)
✓ Response header: content-type = application/json
============================================================
Total assertions passed: 13
============================================================What's Being Tested?
Health Check
Validates that the health endpoint returns 200 and JSON content type.
List Users (GET)
Tests retrieving a list of all users with proper JSON response.
Get User (GET)
Tests retrieving a specific user by ID.
Create User (POST)
Validates that POST returns 201 (Created) status code.
Update User (PUT)
Tests updating a user returns 200 status.
Delete User (DELETE)
Validates DELETE returns 204 (No Content).
List Products (GET)
Tests product listing endpoint.
Extending This Example
Add Request Body Validation
For real APIs that accept request bodies, you can add:
{
"paths": ["/api/users"],
"method": "POST",
"requestBody": {
"name": "John Doe",
"email": "john@example.com"
},
"expectedStatus": 201
}Add More Headers
Test additional response headers:
{
"paths": ["/api/users"],
"method": "GET",
"expectedStatus": 200,
"expectedResponseHeaders": [
["Content-Type", "application/json"],
["X-Total-Count"],
["X-Page"],
["Cache-Control", "no-cache"]
]
}Test Error Cases
Add tests for error scenarios:
{
"paths": ["/api/users/invalid"],
"method": "GET",
"expectedStatus": 404,
"expectedResponseHeaders": [
["Content-Type", "application/json"]
]
}Test Authentication
Add API key testing:
{
"paths": ["/api/users"],
"method": "GET",
"expectedStatus": 401,
"comment": "No auth = 401"
},
{
"paths": ["/api/users"],
"method": "GET",
"additionalRequestHeaders": {
"Authorization": "Bearer valid-token"
},
"expectedStatus": 200
}Related Examples
- Nginx Proxy - Reverse proxy with header transformation
- Microservices - Multi-service communication
- API Gateway - Authentication and rate limiting
Next Steps
- Learn about test.json configuration in detail
- Explore advanced features
- Try other examples