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:
parent
75498c5c65
commit
c4d1aa6fa3
2 changed files with 215 additions and 2 deletions
|
|
@ -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
213
scripts/test-endpoint-formats.sh
Executable 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
|
||||
Loading…
Reference in a new issue