Claude Code Plugins

Community-maintained marketplace

Feedback

endpoint-validator

@mikopbx/Core
487
0

Валидация REST API эндпоинтов на соответствие OpenAPI схеме и консистентность параметров. Использовать при реализации эндпоинтов, ревью кода или перед слиянием изменений API.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name endpoint-validator
description Валидация REST API эндпоинтов на соответствие OpenAPI схеме и консистентность параметров. Использовать при реализации эндпоинтов, ревью кода или перед слиянием изменений API.
allowed-tools Bash, Read, Grep, Glob

MikoPBX Endpoint Validating

Validate MikoPBX REST API endpoints for OpenAPI compliance, parameter consistency, and proper implementation.

What This Skill Does

  1. Validates DataStructure.php - Checks parameter definitions completeness
  2. Validates SaveRecordAction.php - Ensures 7-phase pattern compliance
  3. Tests Schema Validation - Verifies SCHEMA_VALIDATION_STRICT mode
  4. Generates Compliance Report - Provides actionable recommendations

When to Use

Use this skill when:

  • Implementing new API endpoints
  • Modifying existing endpoints
  • Reviewing API code changes
  • Before merging API-related pull requests
  • User asks "validate my API changes"
  • After making changes to DataStructure.php files

Quick Start

Step 1: Identify Files

# Find DataStructure and SaveRecordAction for a resource
RESOURCE="Extensions"  # Or: Providers, IncomingRoutes, etc.

find src/PBXCoreREST/Lib -name "DataStructure.php" | grep -i "$RESOURCE"
find src/PBXCoreREST/Lib -name "SaveRecordAction.php" | grep -i "$RESOURCE"

Expected locations:

  • src/PBXCoreREST/Lib/{Resource}/DataStructure.php
  • src/PBXCoreREST/Lib/{Resource}/SaveRecordAction.php

Step 2: Validate DataStructure

Check for required structure:

class DataStructure
{
    public static function getParameterDefinitions(): array
    {
        return [
            'request' => [
                'param_name' => [
                    'type' => 'string',           // Required
                    'description' => '...',        // Required
                    'example' => 'example_value',  // Required
                    'required' => true,            // Required
                    // Optional constraints:
                    'maxLength' => 255,
                    'pattern' => '^regex$',
                    'enum' => ['value1', 'value2'],
                    'default' => 'default_value',
                ],
            ],
            'response' => [
                // Similar structure for response fields
            ],
        ];
    }
}

Quick Checks:

  • ✅ Has getParameterDefinitions() method
  • ✅ Every parameter has: type, description, example, required
  • ✅ Validation constraints present (min/max, pattern, enum)
  • ❌ NO getParametersConfig() method (legacy)
  • ❌ NO ParameterSanitizationExtractor usage

See: Complete DataStructure Specification

Step 3: Validate SaveRecordAction

Check for 7-phase pattern compliance:

class SaveRecordAction extends BaseSaveAction
{
    public function __invoke(ServerRequestInterface $request): ResponseInterface
    {
        // PHASE 1: Load DataStructure definitions
        $definitions = DataStructure::getParameterDefinitions();

        // PHASE 2: Parse request & detect HTTP method
        $requestData = $this->parseRequest($request);
        $httpMethod = $request->getMethod();

        // PHASE 3: Validate ID if present
        $id = $requestData['id'] ?? null;

        // PHASE 4: Load existing record for PUT/PATCH/DELETE
        $existingRecord = null;
        if (in_array($httpMethod, ['PUT', 'PATCH', 'DELETE']) && $id) {
            $existingRecord = $this->findRecordById($id);
        }

        // PHASE 5: Sanitize & apply defaults (POST only!)
        $sanitized = [];
        foreach ($requestDefs as $param => $def) {
            if (isset($requestData[$param])) {
                $sanitized[$param] = $this->sanitizeValue(...);
            } elseif ($httpMethod === 'POST' && isset($def['default'])) {
                $sanitized[$param] = $def['default'];  // Only on POST!
            }
        }

        // PHASE 6: Validate parameters
        $errors = $this->validateParameters($sanitized, $requestDefs, $httpMethod);

        // PHASE 7: Business logic & persistence
        if ($httpMethod === 'POST') {
            return $this->respondSuccess($this->createRecord($sanitized), 201);
        }
        // ... PUT/PATCH/DELETE handling
    }
}

Critical Checks:

  • ✅ Defaults applied ONLY on POST, never on PATCH
  • ✅ Required validation on POST and PUT, but NOT on PATCH
  • ✅ HTTP method detection present
  • ✅ Comprehensive WHY comments
  • ❌ NO defaults on PATCH (common bug!)

See: Complete 7-Phase Pattern Guide

Top 5 Common Issues

1. 🔴 CRITICAL: Defaults Applied on PATCH

Problem:

// ❌ WRONG - Applies defaults on PATCH too!
$value = $requestData[$param] ?? $def['default'] ?? null;

Why Bad: PATCH is for partial updates. Defaults overwrite existing values.

Fix:

// ✅ CORRECT - Only on POST
if ($httpMethod === 'POST' && !isset($requestData[$param]) && isset($def['default'])) {
    $sanitized[$param] = $def['default'];
}

See: All Anti-Patterns

2. 🔴 CRITICAL: Required Validation on PATCH

Problem:

// ❌ WRONG - Validates required on all methods
if ($def['required'] && !isset($data[$param])) {
    $errors[] = "Required";
}

Why Bad: PATCH allows partial updates. User should update one field without sending all.

Fix:

// ✅ CORRECT - Skip required check for PATCH
if (in_array($httpMethod, ['POST', 'PUT']) && $def['required'] && !isset($data[$param])) {
    $errors[] = "Required";
}

3. 🟡 HIGH: Hardcoded Validation

Problem: Validation rules in SaveRecordAction instead of DataStructure.

Fix: Move all validation constraints to DataStructure:

// In DataStructure.php
'number' => [
    'type' => 'string',
    'pattern' => '^\d{2,8}$',  // Define here
    'maxLength' => 8,
]

// SaveRecordAction uses these constraints automatically

4. 🟡 HIGH: Legacy Methods

Problems:

  • Using getParametersConfig() instead of getParameterDefinitions()
  • Using ParameterSanitizationExtractor class

Fix: Remove legacy code, use modern approach.

5. 🟢 MEDIUM: Missing Validation Constraints

Problem: Parameters missing min/max, pattern, enum constraints.

Fix: Add constraints to DataStructure:

'email' => [
    'type' => 'string',
    'format' => 'email',        // Add format
    'maxLength' => 255,         // Add length limit
]

Validation Workflow

1. Quick Visual Inspection

Read through files looking for:

  • DataStructure has getParameterDefinitions()
  • SaveRecordAction has method detection ($httpMethod) ✅
  • Defaults only in POST conditional ✅
  • Required validation skips PATCH ✅
  • WHY comments present ✅

2. Test with CURL

CONTAINER_ID=$(docker ps --filter "ancestor=mikopbx/mikopbx" --format "{{.ID}}" | head -1)

# Get auth token
TOKEN="your-bearer-token"

# Test POST (should apply defaults)
curl -X POST "https://mikopbx_php83.localhost:8445/pbxcore/api/v3/extensions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"number": "201", "type": "SIP"}' \
  -k -v

# Test PATCH (should NOT apply defaults)
curl -X PATCH "https://mikopbx_php83.localhost:8445/pbxcore/api/v3/extensions/{id}" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"number": "202"}' \
  -k -v

# Verify: status should remain unchanged, not reset to default

3. Generate Report

Use the report template to document findings:

  • DataStructure compliance score
  • SaveRecordAction compliance score
  • Critical issues found
  • Prioritized recommendations

Testing Checklist

Essential tests to verify endpoint behavior:

POST Tests

  • POST with all required succeeds (201)
  • POST with missing required fails (400)
  • POST applies defaults correctly

PUT Tests

  • PUT with all required succeeds (200)
  • PUT with missing required fails (400)
  • PUT on non-existent fails (404)

PATCH Tests (Most Important!)

  • PATCH with partial data succeeds (200)
  • PATCH does NOT apply defaults (verify existing values preserved)
  • PATCH does NOT require all required fields
  • PATCH on non-existent fails (404)

DELETE Tests

  • DELETE existing succeeds (200/204)
  • DELETE non-existent fails (404)

See: Complete Validation Checklist

Output Format

Always provide structured compliance reports:

📋 API Endpoint Validation Report
==================================

🎯 Endpoint: POST /pbxcore/api/v3/extensions
📁 Resource: Extensions

📂 Files Analyzed:
   ✅ DataStructure.php: src/PBXCoreREST/Lib/Extensions/DataStructure.php
   ✅ SaveRecordAction.php: src/PBXCoreREST/Lib/Extensions/SaveRecordAction.php

---

## 🔍 DataStructure Analysis

✅ Structure: COMPLIANT
⚠️  Missing constraints on 3 parameters:
   - user_username: Add pattern validation
   - email: Add format => 'email'

DataStructure Score: 85/100 ✅

---

## 🔍 SaveRecordAction Analysis

❌ CRITICAL ISSUES:
1. Defaults applied on PATCH (Line 87)
   Impact: Partial updates overwrite existing values
   Fix: Wrap default logic in `if ($httpMethod === 'POST')`

2. Missing required validation for PUT (Line 145)
   Impact: PUT allows missing required fields
   Fix: Change to `if (in_array($httpMethod, ['POST', 'PUT']))`

SaveRecordAction Score: 55/100 ❌

---

## 📊 Overall Compliance Score

Total Score: 72/100 ⚠️  Needs Improvement

---

## ✅ Recommendations (Priority Order)

🔴 CRITICAL (Must Fix):
1. Fix PATCH defaults bug (Line 87) - 15 min
2. Add PUT required validation (Line 145) - 10 min

🟡 HIGH PRIORITY:
3. Add validation constraints to DataStructure - 15 min

---

📝 Action Items:
- [ ] Fix PATCH defaults bug
- [ ] Add PUT required validation
- [ ] Add missing constraints
- [ ] Add regression test for PATCH
- [ ] Run full test suite

Full Template: report-template.md

Pro Tips

  1. Always Check PATCH First - Most bugs are in PATCH handling
  2. Look for WHY Comments - They explain critical decisions
  3. Test Actual Behavior - Don't trust code inspection alone
  4. Use Schema Validation - Enable SCHEMA_VALIDATION_STRICT=1
  5. Focus on Defaults - Default application logic is #1 bug source
  6. Check Method Detection - Ensure $httpMethod is actually used

Troubleshooting

Issue: Can't find DataStructure.php

# Search entire codebase
find src -name "DataStructure.php" | grep -i "YourResource"

# If not found, check if resource exists
ls -la src/PBXCoreREST/Lib/ | grep -i "YourResource"

Issue: Schema validation not working

# Check if enabled
docker exec $CONTAINER_ID env | grep SCHEMA_VALIDATION

# If not set, add to docker-compose.yml:
# environment:
#   SCHEMA_VALIDATION_STRICT: 1

Issue: Tests show unexpected behavior

# Check container logs for validation errors
docker exec $CONTAINER_ID tail -100 /storage/usbdisk1/mikopbx/log/php/error.log

Additional Resources

Complete Documentation:

Related Skills:

  • mikopbx-openapi-analyzer - Fetch and analyze OpenAPI spec
  • mikopbx-api-test-generator - Generate pytest tests from spec
  • mikopbx-docker-restart-tester - Test after container restart

Success Criteria

Validation is successful when:

  • ✅ DataStructure has complete parameter definitions
  • ✅ No legacy patterns found
  • ✅ SaveRecordAction follows 7-phase pattern
  • ✅ Defaults only applied on POST
  • ✅ Required validation only on POST/PUT (not PATCH)
  • ✅ All validation from DataStructure, not hardcoded
  • ✅ Schema validation tests pass
  • ✅ PATCH preserves existing values (doesn't apply defaults)
  • ✅ Compliance score ≥ 90/100

Quick Reference Card

Check DataStructure SaveRecordAction
Has modern structure getParameterDefinitions() 7-phase pattern
No legacy code No getParametersConfig() No ParameterSanitizationExtractor
Complete metadata type, description, example WHY comments
Validation constraints min/max, pattern, enum Uses DataStructure rules
Defaults handling Defined in request section Only applied on POST
Required validation Marked with required: true POST & PUT only, not PATCH

Example Validation Session

# 1. Locate files
RESOURCE="Extensions"
find src/PBXCoreREST/Lib -path "*/$RESOURCE/DataStructure.php"
# Output: src/PBXCoreREST/Lib/Extensions/DataStructure.php

# 2. Check DataStructure structure
grep -n "getParameterDefinitions" src/PBXCoreREST/Lib/Extensions/DataStructure.php
# Output: Line 15: public static function getParameterDefinitions(): array

# 3. Check for legacy methods
grep -n "getParametersConfig\|ParameterSanitizationExtractor" \
  src/PBXCoreREST/Lib/Extensions/DataStructure.php
# Output: (none) - Good!

# 4. Check SaveRecordAction for PATCH defaults bug
grep -A 2 "httpMethod.*POST" src/PBXCoreREST/Lib/Extensions/SaveRecordAction.php
# Look for: if ($httpMethod === 'POST' && isset($def['default']))

# 5. Run PATCH test
curl -X PATCH "https://mikopbx_php83.localhost:8445/pbxcore/api/v3/extensions/123" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"number": "202"}' -k | jq '.data.status'
# Verify status didn't change to default value