| 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
- Validates DataStructure.php - Checks parameter definitions completeness
- Validates SaveRecordAction.php - Ensures 7-phase pattern compliance
- Tests Schema Validation - Verifies SCHEMA_VALIDATION_STRICT mode
- 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.phpsrc/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
ParameterSanitizationExtractorusage
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 ofgetParameterDefinitions() - Using
ParameterSanitizationExtractorclass
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
- Always Check PATCH First - Most bugs are in PATCH handling
- Look for WHY Comments - They explain critical decisions
- Test Actual Behavior - Don't trust code inspection alone
- Use Schema Validation - Enable SCHEMA_VALIDATION_STRICT=1
- Focus on Defaults - Default application logic is #1 bug source
- Check Method Detection - Ensure
$httpMethodis 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:
- DataStructure Specification - How to define parameters
- SaveRecordAction Pattern - 7-phase implementation guide
- Validation Checklist - Complete validation checklist
- Anti-Patterns - Common mistakes to avoid
- Report Template - Compliance report format
Related Skills:
mikopbx-openapi-analyzer- Fetch and analyze OpenAPI specmikopbx-api-test-generator- Generate pytest tests from specmikopbx-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