Version: 1.0.0
Category: Testing
Status: Stable
The Testing Protocol defines how AI agents should test API endpoints, validate responses, and ensure correct integration with Structs APIs.
Key Principles:
Query Tests:
Action Tests:
Streaming Tests:
Test Structure:
{
"test": {
"name": "Get player by ID",
"endpoint": "webapp-player-by-id",
"method": "GET",
"url": "http://localhost:8080/api/player/1-11",
"expectedStatus": 200,
"expectedSchema": "schemas/responses.md#/definitions/WebappPlayerResponse",
"validations": [
"response.status === 200",
"response.body.player.id === '1-11'",
"response.body.player.id matches pattern '^1-[0-9]+$'"
]
}
}
Test Structure:
{
"test": {
"name": "Get non-existent player",
"endpoint": "webapp-player-by-id",
"method": "GET",
"url": "http://localhost:8080/api/player/1-999",
"expectedStatus": 404,
"expectedSchema": "schemas/responses.md#/definitions/ErrorResponse",
"validations": [
"response.status === 404",
"response.body.error contains 'not found'",
"response.body.code === 404"
]
}
}
Test Structure:
{
"test": {
"name": "List players with pagination",
"endpoint": "player-list",
"method": "GET",
"url": "http://localhost:1317/structs/player",
"parameters": {
"pagination.limit": 10
},
"expectedStatus": 200,
"validations": [
"response.body.Player is array",
"response.body.Player.length <= 10",
"response.body.pagination exists",
"if response.body.pagination.next_key exists, can fetch next page"
]
}
}
Validate against JSON Schema:
{
"validation": {
"type": "schema",
"schema": "schemas/responses.md#/definitions/WebappPlayerResponse",
"response": "response.body",
"strict": false
}
}
Validate specific fields:
{
"validations": [
{
"field": "response.body.player.id",
"type": "string",
"pattern": "^1-[0-9]+$",
"required": true
},
{
"field": "response.body.player.username",
"type": "string",
"minLength": 3,
"maxLength": 20,
"required": false
}
]
}
Validate data types:
{
"typeValidations": {
"player.id": "string",
"player.stats.total_ore": "integer",
"player.guild": "object|null"
}
}
Test 404 Not Found:
{
"test": {
"name": "Test 404 error",
"endpoint": "webapp-player-by-id",
"method": "GET",
"url": "http://localhost:8080/api/player/1-999",
"expectedStatus": 404,
"expectedError": {
"code": 404,
"error": "Player not found"
},
"validations": [
"response.status === 404",
"response.body.error exists",
"response.body.code === 404"
]
}
}
Test 429 Rate Limit:
{
"test": {
"name": "Test rate limiting",
"endpoint": "webapp-player-by-id",
"method": "GET",
"url": "http://localhost:8080/api/player/1-11",
"scenario": "Make 100+ requests rapidly",
"expectedStatus": 429,
"expectedHeaders": {
"Retry-After": "number",
"X-RateLimit-Limit": "number",
"X-RateLimit-Remaining": "number"
},
"validations": [
"response.status === 429",
"response.headers['Retry-After'] exists",
"parseInt(response.headers['Retry-After']) > 0"
]
}
}
Example: Get Player and Planets:
{
"test": {
"name": "Get player and planets workflow",
"type": "workflow",
"steps": [
{
"step": 1,
"name": "Get player",
"endpoint": "webapp-player-by-id",
"method": "GET",
"url": "http://localhost:8080/api/player/1-11",
"extract": {
"player_id": "response.body.player.id"
},
"validations": [
"response.status === 200",
"response.body.player.id exists"
]
},
{
"step": 2,
"name": "Get player's planets",
"endpoint": "planet-by-player",
"method": "GET",
"url": "http://localhost:1317/structs/planet_by_player/",
"validations": [
"response.status === 200",
"response.body.Planet is array"
]
}
],
"finalValidations": [
"step1.response.body.player.id === step2.request.parameters.playerId",
"step2.response.body.Planet is array"
]
}
}
Test Connection:
{
"test": {
"name": "Test NATS connection",
"type": "streaming",
"connection": {
"url": "nats://localhost:4222",
"timeout": 5000
},
"validations": [
"connection successful",
"can subscribe to subject",
"can receive messages"
]
}
}
Test Event Subscription:
{
"test": {
"name": "Test event reception",
"type": "streaming",
"subscription": {
"subject": "structs.player.*",
"timeout": 10000
},
"validations": [
"subscription successful",
"can receive events",
"event format matches schema",
"event.category is valid"
]
}
}
Valid Test Data:
1-{number}) - Type 1 = Player2-{number}) - Type 2 = Planet0-{number}) - Type 0 = Guild5-{number}) - Type 5 = Struct9-{number}) - Type 9 = FleetInvalid Test Data (for error testing):
1-999, 3-999, etc.invalid-id, 123, etc.Test Report Format:
{
"testReport": {
"testName": "Get player by ID",
"status": "passed|failed|skipped",
"duration": 150,
"request": {
"method": "GET",
"url": "http://localhost:8080/api/player/1-11"
},
"response": {
"status": 200,
"duration": 120
},
"validations": [
{
"name": "Status code check",
"status": "passed",
"expected": 200,
"actual": 200
}
],
"errors": []
}
}
Practice: Test every endpoint you plan to use
Why: Ensures endpoints work as expected in your environment
Practice: Always validate responses against schemas
Why: Catches format changes and errors early
Practice: Test error scenarios (404, 429, 500)
Why: Ensures error handling works correctly
Practice: Test empty results, invalid IDs, boundary values
Why: Handles real-world scenarios
Practice: Test multi-step workflows, not just single endpoints
Why: Ensures integration works end-to-end
Practice: Test rate limiting behavior
Why: Prevents production issues
Practice: Use consistent test data across tests
Why: Makes tests reproducible
Practice: Clean up test data after tests
Why: Prevents test data pollution
{
"test": {
"name": "Get player by ID - Success",
"endpoint": "webapp-player-by-id",
"method": "GET",
"url": "http://localhost:8080/api/player/1-11",
"expectedStatus": 200,
"validations": [
"response.status === 200",
"response.body.player.id === '1-11'",
"response.body.player.id matches '^1-[0-9]+$'",
"response.body.player.username is string or null"
]
}
}
{
"test": {
"name": "Get player by ID - Not Found",
"endpoint": "webapp-player-by-id",
"method": "GET",
"url": "http://localhost:8080/api/player/1-999",
"expectedStatus": 404,
"validations": [
"response.status === 404",
"response.body.error exists",
"response.body.code === 404"
]
}
}
{
"test": {
"name": "Get player and planets workflow",
"type": "workflow",
"steps": [
{
"step": 1,
"endpoint": "webapp-player-by-id",
"url": "http://localhost:8080/api/player/1-11"
},
{
"step": 2,
"endpoint": "planet-by-player",
"url": "http://localhost:1317/structs/planet_by_player/"
}
]
}
}
HTTP Testing:
curl - Command-line testinghttpie - User-friendly HTTP clientPostman - GUI testing toolREST Client - VS Code extensionSchema Validation:
ajv - JSON Schema validator (JavaScript)jsonschema - JSON Schema validator (Python)json-schema-validator - JSON Schema validator (Java)Test Frameworks:
jest - JavaScript testing frameworkpytest - Python testing frameworkjunit - Java testing frameworkprotocols/error-handling.mdprotocols/query-protocol.mdprotocols/action-protocol.mdexamples/errors/examples/workflows/API Documentation Specialist - January 2025
Based on API testing best practices and Structs API structure