endpoint-validator by mikopbx
Валидация REST API эндпоинтов на соответствие OpenAPI схеме и консистентность параметров. Использовать при реализации эндпоинтов, ревью кода или перед слиянием изменений API.
Content & Writing
516 Stars
75 Forks
Updated Nov 7, 2025, 01:57 PM
Why Use This
This skill provides specialized capabilities for mikopbx's codebase.
Use Cases
- Developing new features in the mikopbx repository
- Refactoring existing code to follow mikopbx standards
- Understanding and working with mikopbx's codebase structure
Install Guide
2 steps- 1
Skip this step if Ananke is already installed.
- 2
Skill Snapshot
Auto scan of skill assets. Informational only.
Valid SKILL.md
Checks against SKILL.md specification
Source & Community
Skill Stats
SKILL.md 462 Lines
Total Files 4
Total Size 13.7 KB
License GPL-3.0
---
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
```bash
# 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:
```php
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](reference/datastructure-spec.md)
### Step 3: Validate SaveRecordAction
Check for 7-phase pattern compliance:
```php
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](reference/saveaction-pattern.md)
## Top 5 Common Issues
### 1. 🔴 CRITICAL: Defaults Applied on PATCH
**Problem**:
```php
// ❌ WRONG - Applies defaults on PATCH too!
$value = $requestData[$param] ?? $def['default'] ?? null;
```
**Why Bad**: PATCH is for partial updates. Defaults overwrite existing values.
**Fix**:
```php
// ✅ CORRECT - Only on POST
if ($httpMethod === 'POST' && !isset($requestData[$param]) && isset($def['default'])) {
$sanitized[$param] = $def['default'];
}
```
**See**: [All Anti-Patterns](examples/anti-patterns.md#defaults-applied-on-patch)
### 2. 🔴 CRITICAL: Required Validation on PATCH
**Problem**:
```php
// ❌ 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**:
```php
// ✅ 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:
```php
// 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:
```php
'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
```bash
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](templates/report-template.md) 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](reference/validation-checklist.md)
## 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](templates/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
```bash
# 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
```bash
# 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
```bash
# 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](reference/datastructure-spec.md) - How to define parameters
- [SaveRecordAction Pattern](reference/saveaction-pattern.md) - 7-phase implementation guide
- [Validation Checklist](reference/validation-checklist.md) - Complete validation checklist
- [Anti-Patterns](examples/anti-patterns.md) - Common mistakes to avoid
- [Report Template](templates/report-template.md) - Compliance report format
**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
```bash
# 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
```