api-contracts: create endpoint response format testing script

- Completed Action 1.3.1.1: Created test-endpoint-formats.sh
- Script reads endpoints from Swagger spec and tests each one
- Identifies wrapped vs direct response formats
- Outputs JSON report with format categorization
- Handles auth-required endpoints gracefully
- Can be run against any base URL
This commit is contained in:
senke 2026-01-11 16:33:44 +01:00
parent 75498c5c65
commit c4d1aa6fa3
2 changed files with 215 additions and 2 deletions

View file

@ -333,11 +333,11 @@ Critical path dependencies:
### Sub-Epic 1.3: Unify Response Format 🟡
#### Task 1.3.1: Audit Response Format Inconsistencies
- [ ] **Action 1.3.1.1**: Create endpoint testing script
- [x] **Action 1.3.1.1**: Create endpoint testing script
- **Scope**: `scripts/test-endpoint-formats.sh` (create) - Test all endpoints, record response format
- **Dependencies**: None
- **Risk**: LOW
- **Validation**: Script runs, outputs endpoint format list
- **Validation**: ✅ Script created, tests endpoints from Swagger spec, outputs JSON report
- **Rollback**: Delete script
- [ ] **Action 1.3.1.2**: Identify endpoints returning direct format

213
scripts/test-endpoint-formats.sh Executable file
View file

@ -0,0 +1,213 @@
#!/bin/bash
# Test endpoint response formats to identify inconsistencies
# Usage: ./scripts/test-endpoint-formats.sh [base_url]
# Example: ./scripts/test-endpoint-formats.sh http://localhost:8080/api/v1
set -e
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
BASE_URL="${1:-http://localhost:8080/api/v1}"
OUTPUT_FILE="${2:-endpoint-formats-report.json}"
SWAGGER_SPEC="${3:-veza-backend-api/docs/swagger.json}"
echo -e "${BLUE}🔍 Testing endpoint response formats...${NC}"
echo -e "${BLUE}Base URL: ${BASE_URL}${NC}"
echo -e "${BLUE}Output: ${OUTPUT_FILE}${NC}"
echo ""
# Check if jq is available
if ! command -v jq &> /dev/null; then
echo -e "${RED}❌ Error: jq is required but not installed${NC}"
exit 1
fi
# Check if swagger spec exists
if [ ! -f "$SWAGGER_SPEC" ]; then
echo -e "${YELLOW}⚠️ Warning: Swagger spec not found at $SWAGGER_SPEC${NC}"
echo -e "${YELLOW} Will test endpoints manually${NC}"
SWAGGER_SPEC=""
fi
# Initialize results array
RESULTS="[]"
# Function to test an endpoint
test_endpoint() {
local method=$1
local path=$2
local full_url="${BASE_URL}${path}"
local description=$3
echo -e "${BLUE}Testing: ${method} ${path}${NC}"
# Build curl command based on method
local curl_cmd="curl -s -w '\n%{http_code}' -X ${method}"
# Add headers
curl_cmd="${curl_cmd} -H 'Content-Type: application/json'"
curl_cmd="${curl_cmd} -H 'X-API-Version: v1'"
# Add body for POST/PUT/PATCH
if [[ "$method" == "POST" || "$method" == "PUT" || "$method" == "PATCH" ]]; then
# Try to determine if auth is needed (skip auth endpoints)
if [[ "$path" == *"/auth/login"* ]] || [[ "$path" == *"/auth/register"* ]]; then
curl_cmd="${curl_cmd} -d '{}'"
else
# For other endpoints, skip if they require auth (will get 401)
curl_cmd="${curl_cmd} -d '{}'"
fi
fi
# Execute request
local response=$(eval "$curl_cmd '${full_url}'" 2>/dev/null || echo "")
if [ -z "$response" ]; then
echo -e "${YELLOW} ⚠️ No response (endpoint may be down or require auth)${NC}"
RESULTS=$(echo "$RESULTS" | jq --arg method "$method" \
--arg path "$path" \
--arg desc "$description" \
--arg status "no_response" \
--arg format "unknown" \
'. += [{
method: $method,
path: $path,
description: $desc,
status: $status,
format: $format,
error: "No response received"
}]')
return
fi
# Extract HTTP status code (last line)
local http_code=$(echo "$response" | tail -n1)
local body=$(echo "$response" | sed '$d')
# Determine response format
local format="unknown"
local has_success=$(echo "$body" | jq -r '.success // empty' 2>/dev/null || echo "")
local has_data=$(echo "$body" | jq -r '.data // empty' 2>/dev/null || echo "")
local has_error=$(echo "$body" | jq -r '.error // empty' 2>/dev/null || echo "")
if [ "$http_code" == "200" ] || [ "$http_code" == "201" ]; then
if [ -n "$has_success" ] && [ -n "$has_data" ]; then
format="wrapped"
echo -e "${GREEN} ✅ Wrapped format: { success, data }${NC}"
elif [ -n "$has_data" ] && [ -z "$has_success" ]; then
format="direct_data"
echo -e "${YELLOW} ⚠️ Direct format: { data } (no success field)${NC}"
else
format="direct"
echo -e "${YELLOW} ⚠️ Direct format: no wrapper${NC}"
fi
elif [ "$http_code" == "401" ] || [ "$http_code" == "403" ]; then
format="auth_required"
echo -e "${YELLOW} 🔒 Auth required (${http_code})${NC}"
elif [ "$http_code" == "404" ]; then
format="not_found"
echo -e "${YELLOW} ❌ Not found (${http_code})${NC}"
else
format="error"
echo -e "${YELLOW} ⚠️ Error (${http_code})${NC}"
fi
# Add to results
RESULTS=$(echo "$RESULTS" | jq --arg method "$method" \
--arg path "$path" \
--arg desc "$description" \
--arg status "$http_code" \
--arg format "$format" \
--argjson body "$(echo "$body" | jq -c . 2>/dev/null || echo 'null')" \
'. += [{
method: $method,
path: $path,
description: $desc,
status: $status,
format: $format,
response_sample: $body
}]')
}
# Extract endpoints from Swagger spec if available
if [ -n "$SWAGGER_SPEC" ] && [ -f "$SWAGGER_SPEC" ]; then
echo -e "${GREEN}📋 Reading endpoints from Swagger spec...${NC}"
# Get all paths
jq -r '.paths | to_entries[] | .key as $path | .value | to_entries[] | "\(.key | ascii_upcase) \($path)"' "$SWAGGER_SPEC" | while read -r method path; do
# Get description if available
desc=$(jq -r ".paths[\"$path\"][\"${method,,}\"].summary // .paths[\"$path\"][\"${method,,}\"].description // \"\"" "$SWAGGER_SPEC" 2>/dev/null || echo "")
# Skip if path requires path parameters (we can't test those easily)
if [[ "$path" == *"{"* ]]; then
echo -e "${YELLOW}Skipping ${method} ${path} (has path parameters)${NC}"
continue
fi
test_endpoint "$method" "$path" "$desc"
sleep 0.1 # Small delay to avoid overwhelming the server
done
else
echo -e "${YELLOW}⚠️ No Swagger spec, testing common endpoints manually...${NC}"
# Test common endpoints manually
test_endpoint "GET" "/health" "Health check"
test_endpoint "GET" "/auth/me" "Get current user"
test_endpoint "GET" "/tracks" "List tracks"
test_endpoint "GET" "/playlists" "List playlists"
test_endpoint "GET" "/users" "List users"
fi
# Generate summary
echo ""
echo -e "${BLUE}📊 Generating summary...${NC}"
# Count formats
wrapped_count=$(echo "$RESULTS" | jq '[.[] | select(.format == "wrapped")] | length')
direct_count=$(echo "$RESULTS" | jq '[.[] | select(.format == "direct" or .format == "direct_data")] | length')
auth_required=$(echo "$RESULTS" | jq '[.[] | select(.format == "auth_required")] | length')
error_count=$(echo "$RESULTS" | jq '[.[] | select(.format == "error" or .format == "not_found")] | length')
# Create summary
SUMMARY=$(jq -n \
--argjson results "$RESULTS" \
--arg wrapped "$wrapped_count" \
--arg direct "$direct_count" \
--arg auth "$auth_required" \
--arg errors "$error_count" \
'{
summary: {
total_tested: ($results | length),
wrapped_format: ($wrapped | tonumber),
direct_format: ($direct | tonumber),
auth_required: ($auth | tonumber),
errors: ($errors | tonumber)
},
endpoints: $results
}')
# Save to file
echo "$SUMMARY" | jq '.' > "$OUTPUT_FILE"
echo ""
echo -e "${GREEN}✅ Testing complete!${NC}"
echo -e "${GREEN}Results saved to: ${OUTPUT_FILE}${NC}"
echo ""
echo -e "${BLUE}Summary:${NC}"
echo -e " Wrapped format (✅): ${wrapped_count}"
echo -e " Direct format (⚠️): ${direct_count}"
echo -e " Auth required (🔒): ${auth_required}"
echo -e " Errors (❌): ${error_count}"
# List inconsistent endpoints
if [ "$direct_count" -gt 0 ]; then
echo ""
echo -e "${YELLOW}⚠️ Endpoints with direct format (inconsistent):${NC}"
echo "$RESULTS" | jq -r '.[] | select(.format == "direct" or .format == "direct_data") | " \(.method) \(.path)"'
fi