| name | route-tester |
| description | Test authenticated API routes in ActionPhase using JWT Bearer token authentication. Use when testing API endpoints, validating route functionality, debugging authentication issues, or verifying request/response data. Includes patterns for using backend/scripts/api-test.sh and curl with proper authorization headers. |
ActionPhase Route Tester Skill
Purpose
This skill provides patterns for testing authenticated routes in ActionPhase using JWT Bearer token authentication with the Go backend.
When to Use This Skill
- Testing new API endpoints
- Validating route functionality after changes
- Debugging authentication issues
- Testing POST/PUT/DELETE operations
- Verifying request/response data
- End-to-end API testing
- Integration testing before E2E tests
ActionPhase Authentication Overview
ActionPhase uses:
- JWT Bearer tokens (Authorization header)
- Token lifetime: 15 minutes (access token)
- Refresh tokens: 7 days (stored in database sessions)
- Token storage: Frontend stores in memory + localStorage
- Backend: Go with Chi router + JWT middleware
See: /docs/adrs/003-authentication-strategy.md for complete details
Testing Methods
Method 1: api-test.sh (RECOMMENDED)
The api-test.sh script handles authentication and provides convenient commands for testing.
Location: backend/scripts/api-test.sh
Quick Start
# 1. Login and save token
./backend/scripts/api-test.sh login-player
# 2. Test endpoints
./backend/scripts/api-test.sh games
./backend/scripts/api-test.sh game 164
./backend/scripts/api-test.sh characters 164
Available Commands
Authentication:
./api-test.sh login [username] # Login as any user (default: TestPlayer1)
./api-test.sh login-gm # Login as TestGM
./api-test.sh login-player # Login as TestPlayer1
./api-test.sh test-token # Verify current token is valid
API Endpoints:
./api-test.sh health # Check backend health
./api-test.sh status # Complete status check
./api-test.sh games # List all games
./api-test.sh game [id] # Get game details (default: 164)
./api-test.sh characters [game_id] # Get characters (default: 164)
./api-test.sh posts [game_id] # Get posts (default: 164)
./api-test.sh comments <post_id> # Get comments for post
Create Operations:
./api-test.sh create-post [game_id] [character_id] [content]
./api-test.sh create-comment <post_id> [character_id] [content]
Feature Testing:
./api-test.sh test-mentions # End-to-end mention testing
What the Script Does
- Logs in via
/api/v1/auth/loginwith test credentials - Extracts JWT token from response
- Saves token to
/tmp/api-token.txt - Uses token in
Authorization: Bearer <token>header for all requests - Parses responses with
jqfor readability
Script Output
The script outputs:
- Colored status indicators (✅/❌)
- JSON responses formatted with jq
- Error messages if requests fail
- Token validation results
Method 2: Manual curl with Token
Use the token saved by api-test.sh for manual testing:
# Get the token
TOKEN=$(cat /tmp/api-token.txt)
# Use in curl requests
curl -s -H "Authorization: Bearer $TOKEN" \
http://localhost:3000/api/v1/games | jq '.'
Manual curl Patterns
GET Request:
curl -s -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/games/164" | jq '.'
POST Request:
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"title": "New Game", "description": "Test game"}' \
"http://localhost:3000/api/v1/games" | jq '.'
PUT Request:
curl -s -X PUT \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"title": "Updated Title"}' \
"http://localhost:3000/api/v1/games/164" | jq '.'
DELETE Request:
curl -s -X DELETE \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/games/164" | jq '.'
Common Testing Patterns
Test New API Endpoint
# 1. Login first
./backend/scripts/api-test.sh login-player
# 2. Test the endpoint
curl -s -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/your-new-endpoint" | jq '.'
# 3. Verify response structure
# 4. Check database changes if applicable
Test Character Creation Flow
# 1. Login as player
./backend/scripts/api-test.sh login-player
# 2. Create character
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{
"game_id": 164,
"name": "Test Character",
"character_sheet": {"class": "Warrior", "level": 1}
}' \
"http://localhost:3000/api/v1/characters" | jq '.'
# 3. Verify in database
# 4. Login as GM and test approval workflow
./backend/scripts/api-test.sh login-gm
Test Phase Transition
# Login as GM
./backend/scripts/api-test.sh login-gm
# Advance phase
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"game_id": 164}' \
"http://localhost:3000/api/v1/phases/advance" | jq '.'
# Verify phase changed
./backend/scripts/api-test.sh game 164 | jq '.current_phase'
Test Private Messages
# Login as Player 1
./backend/scripts/api-test.sh login TestPlayer1
# Send message to Player 2
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{
"recipient_character_id": 1320,
"content": "Test private message"
}' \
"http://localhost:3000/api/v1/games/164/messages/private" | jq '.'
# Login as Player 2 and check messages
./backend/scripts/api-test.sh login TestPlayer2
./backend/scripts/api-test.sh posts 164
Test with Query Parameters
curl -s -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/games/164/posts?limit=10&offset=0" | jq '.'
Test Credentials
Available Test Users:
| Username | Password | Role |
|---|---|---|
| TestGM | testpassword123 | Game Master |
| TestPlayer1 | testpassword123 | Player |
| TestPlayer2 | testpassword123 | Player |
| TestPlayer3 | testpassword123 | Player |
Test Game: Game ID 164 (use this for testing)
See: .claude/context/TEST_DATA.md for complete test fixture documentation
API Structure
Base URL
http://localhost:3000/api/v1
Route Structure
All routes follow REST conventions:
/api/v1/{resource}
/api/v1/{resource}/{id}
/api/v1/{resource}/{id}/{sub-resource}
Examples:
/api/v1/games- List games/api/v1/games/164- Get game 164/api/v1/games/164/characters- List characters in game 164/api/v1/games/164/posts- List posts in game 164
Authentication Endpoints
POST /api/v1/auth/login # Login (returns JWT)
POST /api/v1/auth/logout # Logout
GET /api/v1/auth/me # Get current user
POST /api/v1/auth/refresh # Refresh access token
Main Resource Endpoints
Games:
GET /api/v1/games # List games
POST /api/v1/games # Create game (GM only)
GET /api/v1/games/{id} # Get game details
PUT /api/v1/games/{id} # Update game (GM only)
DELETE /api/v1/games/{id} # Delete game (GM only)
Characters:
GET /api/v1/games/{game_id}/characters # List characters
POST /api/v1/characters # Create character
GET /api/v1/characters/{id} # Get character
PUT /api/v1/characters/{id} # Update character
POST /api/v1/characters/{id}/approve # Approve (GM only)
POST /api/v1/characters/{id}/reject # Reject (GM only)
Messaging:
GET /api/v1/games/{game_id}/posts # Common room posts
POST /api/v1/games/{game_id}/posts # Create post
GET /api/v1/games/{game_id}/posts/{id}/comments # Get comments
POST /api/v1/games/{game_id}/posts/{id}/comments # Create comment
GET /api/v1/games/{game_id}/messages/private # Private messages
POST /api/v1/games/{game_id}/messages/private # Send private message
Phases:
POST /api/v1/phases/advance # Advance phase (GM only)
GET /api/v1/games/{game_id}/phases/current # Get current phase
See: .claude/reference/API_DOCUMENTATION.md for complete API reference
Testing Checklist
Before testing a route:
- Backend server is running (
just dev) - Database is migrated (
just migrate) - Test fixtures are loaded (if needed)
- You have a valid token (
./api-test.sh login-player) - You know the full route path
- You know the HTTP method (GET/POST/PUT/DELETE)
- You have the request body prepared (if POST/PUT)
- You know the expected response structure
- You can verify changes (database, logs, etc.)
Verifying Database Changes
After testing routes that modify data:
# Connect to PostgreSQL
PGPASSWORD=example psql -h localhost -U postgres -d actionphase
# Check specific tables
actionphase=# SELECT * FROM games WHERE id = 164;
actionphase=# SELECT * FROM characters WHERE game_id = 164;
actionphase=# SELECT * FROM posts WHERE game_id = 164 ORDER BY created_at DESC LIMIT 5;
actionphase=# SELECT * FROM sessions WHERE username = 'TestPlayer1';
# Or use justfile command
just psql
Quick queries:
-- Latest posts
SELECT id, character_id, content, created_at
FROM posts
WHERE game_id = 164
ORDER BY created_at DESC
LIMIT 10;
-- Character mentions
SELECT p.id, p.content, p.mentioned_character_ids
FROM posts p
WHERE game_id = 164
AND mentioned_character_ids IS NOT NULL
ORDER BY created_at DESC;
-- Current phase
SELECT id, title, current_phase, phase_number
FROM games
WHERE id = 164;
Debugging Failed Tests
401 Unauthorized
Possible causes:
- No token provided
- Token expired (15 minute lifetime)
- Invalid token format
- JWT secret mismatch
Solutions:
# Check if backend is running
curl http://localhost:3000/health
# Get a fresh token
./backend/scripts/api-test.sh login-player
# Verify token works
./backend/scripts/api-test.sh test-token
# Check token format (should start with "eyJ")
cat /tmp/api-token.txt
403 Forbidden
Possible causes:
- User lacks required permissions
- Not the GM for GM-only routes
- Not the owner of the resource
- Character not approved yet
Solutions:
# For GM-only routes, login as GM
./backend/scripts/api-test.sh login-gm
# Check user info
./backend/scripts/api-test.sh test-token
# Verify ownership in database
just psql
404 Not Found
Possible causes:
- Incorrect URL
- Resource doesn't exist
- Route not implemented yet
- Typo in endpoint path
Solutions:
# Check route exists in backend/pkg/http/root.go
grep -r "your-route" backend/pkg/http/
# Verify resource exists
just psql
# Then: SELECT * FROM games WHERE id = 164;
# Check server logs
# (server should print route registrations on startup)
500 Internal Server Error
Possible causes:
- Database connection issue
- Missing required fields
- Validation error
- Application panic/error
Solutions:
# Check server logs in terminal
# Backend prints detailed error logs with correlation IDs
# Check database is running
docker ps | grep postgres
# Verify request body structure
# Compare with models in backend/pkg/core/models.go
# Check correlation ID in error response
# Search logs for that correlation ID
Testing Workflow
1. Unit Tests → 2. API Tests → 3. Manual Tests → 4. E2E Tests
This skill covers steps 2 and 3.
Step-by-Step Testing Flow
- Write/modify backend code
- Run unit tests:
just test-mocks - Start backend:
just dev - Test API with curl/api-test.sh ← This skill
- Verify in database:
just psql - Test in UI manually
- Write E2E tests: Only after API works
See: .claude/context/TESTING.md for complete testing strategy
Integration with Other Tools
Use with Test Fixtures
# Load test fixtures
./backend/pkg/db/test_fixtures/apply_e2e.sh
# Now test with known data
./backend/scripts/api-test.sh game 164
./backend/scripts/api-test.sh characters 164
Use Before E2E Tests
# 1. Test API endpoint works
./backend/scripts/api-test.sh create-post 164 1319 "Test content"
# 2. Verify response structure is correct
# 3. NOW write Playwright test
# The API endpoint is confirmed working
Use with justfile Commands
# justfile integrates api-test.sh
just api-login # Login as player
just api-login-gm # Login as GM
just api-games # List games
just api-game 164 # Get game 164
Environment Variables
# Override API base URL
API_BASE_URL=http://localhost:3000 ./backend/scripts/api-test.sh games
# Use different port
API_BASE_URL=http://localhost:8080 ./backend/scripts/api-test.sh health
Common Scenarios
Scenario 1: Testing a New POST Endpoint
# 1. Start backend
just dev
# 2. Login
./backend/scripts/api-test.sh login-player
# 3. Test endpoint
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"field": "value"}' \
"http://localhost:3000/api/v1/your-endpoint" | jq '.'
# 4. Verify in database
just psql
# Then: SELECT * FROM your_table ORDER BY created_at DESC LIMIT 1;
# 5. Test error cases
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{"invalid": "data"}' \
"http://localhost:3000/api/v1/your-endpoint" | jq '.'
# Should return 400 with validation error
Scenario 2: Testing Permission-Based Access
# Test as Player (should fail)
./backend/scripts/api-test.sh login-player
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/phases/advance" | jq '.'
# Should return 403
# Test as GM (should succeed)
./backend/scripts/api-test.sh login-gm
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/phases/advance" | jq '.'
# Should return 200
Scenario 3: End-to-End Feature Test
# Complete workflow test
echo "=== Testing Character Creation & Approval ==="
# 1. Player creates character
./backend/scripts/api-test.sh login-player
CHAR=$(curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
-H "Content-Type: application/json" \
-d '{
"game_id": 164,
"name": "Test Character",
"character_sheet": {"class": "Mage"}
}' \
"http://localhost:3000/api/v1/characters")
CHAR_ID=$(echo "$CHAR" | jq -r '.id')
echo "Created character: $CHAR_ID"
# 2. GM approves character
./backend/scripts/api-test.sh login-gm
curl -s -X POST \
-H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/characters/$CHAR_ID/approve" | jq '.'
# 3. Verify character is approved
curl -s -H "Authorization: Bearer $(cat /tmp/api-token.txt)" \
"http://localhost:3000/api/v1/characters/$CHAR_ID" | jq '.status'
# Should return "approved"
echo "✅ Character workflow complete"
Key Files
- Testing script:
backend/scripts/api-test.sh - API routes:
backend/pkg/http/root.go - Handler implementations:
backend/pkg/*/api.go - Test fixtures:
backend/pkg/db/test_fixtures/*.sql - justfile: Development commands that wrap api-test.sh
Related Skills & Context
- backend-dev-guidelines - Patterns for implementing API endpoints
- database-operations - Database schema and query patterns
- authentication - JWT authentication details
- test-fixtures - Test data setup and usage
Context Files:
.claude/context/TESTING.md- Testing strategy.claude/context/TEST_DATA.md- Test fixtures reference.claude/context/ARCHITECTURE.md- Request flow.claude/reference/API_DOCUMENTATION.md- Complete API reference
Skill Status: COMPLETE ✅
Authentication: JWT Bearer tokens ✅
Testing Script: backend/scripts/api-test.sh ✅
Integration: Works with test fixtures, justfile, E2E tests ✅