Claude
Skills
Sign in
Back

api-integration-testing

Included with Lifetime
$97 forever

Test .NET API endpoints with curl to validate JWT authentication, CRUD operations, business isolation, and Clean Architecture compliance

Backend & APIs

What this skill does


# API Integration Testing Skill

Use this skill to perform integration testing of .NET microservices using curl and command-line tools.

## When to Use
- After implementing API endpoints
- After fixing backend bugs
- Before deploying backend changes
- During QA validation
- For security testing

## What This Skill Does

### 1. JWT Authentication Testing
Validates security implementation:
- Test endpoints without token (expect 401)
- Test with invalid token (expect 401)
- Test with wrong role (expect 403)
- Test with correct role (expect 200)

### 2. CRUD Operations Testing
Tests all API operations:
- CREATE: POST request creates resource
- READ: GET request returns data
- UPDATE: PUT request modifies resource
- DELETE: DELETE request removes resource

### 3. Business Isolation Testing
Verifies multi-tenancy security:
- Cannot access other business data
- Queries filter by business_id from JWT
- Cross-business access returns 404

### 4. Validation Testing
Checks input validation:
- Missing required fields return 400
- Invalid formats return 400
- Error messages are user-friendly

### 5. Health Check Testing
Verifies monitoring:
- /health endpoint responds 200
- Database connectivity checked

## Testing Tools

### Bash Commands Available
- `curl` - HTTP requests to API
- `dotnet build` - Compile verification
- `dotnet test` - Run unit tests
- `docker-compose` - Start services
- `jq` - Parse JSON responses (if available)

## Expected Inputs
- API base URL (e.g., http://localhost:8003/api/scheduling)
- Endpoints to test
- JWT tokens for different roles
- Test data payloads

## Testing Workflow

### Step 1: Build Verification
```bash
cd {context}/{context}-api
dotnet build
```
**Expected**: 0 errors, 0 warnings

### Step 2: Start Service
```bash
docker-compose up -d {context}_api
```
**Expected**: Container starts successfully

### Step 3: Test Health
```bash
curl -f http://localhost:{port}/health
```
**Expected**: HTTP 200

### Step 4: Test Authentication
```bash
# No token (should fail)
curl -i http://localhost:{port}/api/{context}/endpoint
# Expected: 401 Unauthorized

# Invalid token (should fail)
curl -i -H "Authorization: Bearer invalid" \
  http://localhost:{port}/api/{context}/endpoint
# Expected: 401 Unauthorized

# Valid token (should succeed)
curl -i -H "Authorization: Bearer ${VALID_TOKEN}" \
  http://localhost:{port}/api/{context}/endpoint
# Expected: 200 OK
```

### Step 5: Test CRUD
```bash
# CREATE
curl -X POST \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"name":"Test","value":123}' \
  http://localhost:{port}/api/{context}/items

# READ
curl -H "Authorization: Bearer ${TOKEN}" \
  http://localhost:{port}/api/{context}/items/{id}

# UPDATE
curl -X PUT \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"name":"Updated","value":456}' \
  http://localhost:{port}/api/{context}/items/{id}

# DELETE
curl -X DELETE \
  -H "Authorization: Bearer ${TOKEN}" \
  http://localhost:{port}/api/{context}/items/{id}
```

### Step 6: Test Business Isolation
```bash
# Create with Business A token
ITEM_ID=$(curl -X POST \
  -H "Authorization: Bearer ${BUSINESS_A_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"name":"A Item"}' \
  http://localhost:{port}/api/{context}/items | jq -r '.id')

# Try to access with Business B token (should fail)
curl -i -H "Authorization: Bearer ${BUSINESS_B_TOKEN}" \
  http://localhost:{port}/api/{context}/items/${ITEM_ID}
# Expected: 404 Not Found
```

### Step 7: Test Validation
```bash
# Missing required field
curl -i -X POST \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"value":123}' \
  http://localhost:{port}/api/{context}/items
# Expected: 400 Bad Request with validation error
```

### Step 8: Verify Clean Architecture
```bash
# Check response is DTO, not entity
# Should NOT have:
# - EF Core navigation properties
# - Internal business logic methods
# - Audit fields (CreatedAt, UpdatedAt)

# Should have:
# - Only data properties
# - Clean, simple structure
```

## Test Scripts Examples

### Example 1: Schedule API Test
```bash
#!/bin/bash
API_URL="http://localhost:8003/api/scheduling"
TOKEN="eyJhbGc..." # Valid JWT token

echo "Testing Schedule API..."

# Test health
echo "1. Health check..."
curl -f ${API_URL:0:-15}/health || echo "FAIL: Health check"

# Test auth
echo "2. Auth test (no token)..."
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" ${API_URL}/schedules)
[ "$RESPONSE" = "401" ] && echo "PASS" || echo "FAIL: Expected 401, got $RESPONSE"

# Test CREATE
echo "3. Create schedule..."
CREATED=$(curl -X POST \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"employeeId":"123","date":"2025-01-20","startTime":"09:00","endTime":"17:00"}' \
  ${API_URL}/schedules)
SCHEDULE_ID=$(echo $CREATED | jq -r '.id')
echo "Created schedule: $SCHEDULE_ID"

# Test READ
echo "4. Read schedule..."
curl -H "Authorization: Bearer ${TOKEN}" \
  ${API_URL}/schedules/${SCHEDULE_ID} | jq '.'

# Test UPDATE
echo "5. Update schedule..."
curl -X PUT \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"employeeId":"123","date":"2025-01-20","startTime":"09:00","endTime":"18:00"}' \
  ${API_URL}/schedules/${SCHEDULE_ID} | jq '.'

# Test DELETE
echo "6. Delete schedule..."
curl -X DELETE \
  -H "Authorization: Bearer ${TOKEN}" \
  ${API_URL}/schedules/${SCHEDULE_ID}

# Verify deleted
echo "7. Verify deleted..."
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer ${TOKEN}" \
  ${API_URL}/schedules/${SCHEDULE_ID})
[ "$RESPONSE" = "404" ] && echo "PASS: Deleted" || echo "FAIL: Still exists"

echo "Tests complete!"
```

### Example 2: Business Isolation Test
```bash
#!/bin/bash
API_URL="http://localhost:8003/api/scheduling"
BUSINESS_A_TOKEN="token_for_business_a"
BUSINESS_B_TOKEN="token_for_business_b"

echo "Testing business isolation..."

# Create schedule with Business A
SCHEDULE_ID=$(curl -X POST \
  -H "Authorization: Bearer ${BUSINESS_A_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"employeeId":"123","date":"2025-01-20"}' \
  ${API_URL}/schedules | jq -r '.id')

echo "Created schedule $SCHEDULE_ID for Business A"

# Try to access with Business B (should fail)
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer ${BUSINESS_B_TOKEN}" \
  ${API_URL}/schedules/${SCHEDULE_ID})

if [ "$RESPONSE" = "404" ]; then
  echo "PASS: Business B cannot access Business A data"
else
  echo "FAIL: Business B can access Business A data (Security issue!)"
  exit 1
fi
```

## Validation Checklist
- [ ] Build succeeds (dotnet build)
- [ ] Tests pass (dotnet test)
- [ ] Health check responds 200
- [ ] JWT required (401 without token)
- [ ] Authorization enforced (403 wrong role)
- [ ] CREATE returns 201
- [ ] READ returns 200
- [ ] UPDATE returns 200
- [ ] DELETE returns 204/200
- [ ] Business isolation works (404 for other business)
- [ ] Validation returns 400
- [ ] Error messages user-friendly
- [ ] Swagger documentation correct

## Deliverables
- Test execution results
- Pass/fail for each test case
- HTTP response codes captured
- Error messages (if any)
- Security test results
- Recommendations for fixes

## Common Test Failures

### 401 when token provided
**Cause**: Token validation misconfigured
**Check**: JWT_SECRET, Issuer, Audience in appsettings.json

### 403 for correct role
**Cause**: Policy not matching claim
**Check**: Authorization policy definition, claim names

### Can access other business data
**Cause**: Missing business_id filter
**Fix**: CRITICAL SECURITY ISSUE - Add filtering immediately

### 500 errors
**Cause**: Unhandled exceptions
**Check**: Application logs, add try-catch, validation

This skill ensures comprehensive API testing covering functionality, security, and architectural compliance.

Related in Backend & APIs