|
1 | 1 | # Changelog |
2 | 2 |
|
3 | 3 | All notable changes to `laravel-api-documentation` will be documented in this file. |
| 4 | + |
| 5 | +## [Unreleased] - 2025-10-21 |
| 6 | + |
| 7 | +### Added |
| 8 | + |
| 9 | +#### Enhanced Request Parameter Documentation |
| 10 | + |
| 11 | +- **Enum Value Extraction from Rule::in()**: Added automatic extraction of enum values from `Rule::in()` validation rules |
| 12 | + - Location: `src/Services/RequestAnalyzer.php` |
| 13 | + - **Supported patterns:** |
| 14 | + - Direct arrays: `Rule::in(['value1', 'value2', 'value3'])` |
| 15 | + - PHP 8.1+ enums: `Rule::in(MyEnum::cases())` or `Rule::in(MyEnum::values())` |
| 16 | + - Class constants: `Rule::in(MyEnum::ALL_VALUES)` |
| 17 | + - **Automatic class name resolution:** |
| 18 | + - Parses `use` statements from FormRequest files |
| 19 | + - Resolves short class names to fully qualified names |
| 20 | + - Example: `BoxPerformanceLevelType` → `App\Enums\BoxPerformanceLevelType` |
| 21 | + - **Enum value extraction methods:** |
| 22 | + - `extractEnumValuesFromRuleInArgument()`: Main extraction logic |
| 23 | + - `extractValuesFromPhpEnum()`: PHP 8.1+ backed enum support |
| 24 | + - `extractValuesFromCustomEnum()`: Custom enum classes with `values()` method |
| 25 | + - `extractUseStatementsFromAst()`: AST-based use statement parsing |
| 26 | + - **Generated OpenAPI schema:** |
| 27 | + - Type: Inferred from validation rules |
| 28 | + - Enum: Array of all possible values |
| 29 | + - Description: "Must be one of: {values}" |
| 30 | + - Example: First enum value |
| 31 | + - **Before/After comparison:** |
| 32 | + ```json |
| 33 | + // Before (without enum extraction) |
| 34 | + { |
| 35 | + "type": "string", |
| 36 | + "description": "Can be null. Must be a string." |
| 37 | + } |
| 38 | + |
| 39 | + // After (with automatic enum extraction) |
| 40 | + { |
| 41 | + "type": "string", |
| 42 | + "description": "Can be null. Must be a string. Must be one of: mini, starter, fully_managed, pro, pro_xl, business, business_xl, business_xxl, enterprise, enteprise_xl.", |
| 43 | + "enum": ["mini", "starter", "fully_managed", "pro", "pro_xl", "business", "business_xl", "business_xxl", "enterprise", "enteprise_xl"], |
| 44 | + "example": "mini" |
| 45 | + } |
| 46 | + ``` |
| 47 | + |
| 48 | +#### Runtime Response Capture System |
| 49 | +- **CaptureApiResponseMiddleware**: Middleware that captures actual API responses during testing for documentation generation |
| 50 | + - Location: `src/Middleware/CaptureApiResponseMiddleware.php` |
| 51 | + - Automatically captures response schemas during test execution |
| 52 | + - Production-safe with explicit environment checks |
| 53 | + - Stores captured responses in `.schemas/responses/` directory |
| 54 | + - Supports sensitive data sanitization |
| 55 | + |
| 56 | +- **CapturedResponseRepository**: Service for managing stored captured responses |
| 57 | + - Location: `src/Services/CapturedResponseRepository.php` |
| 58 | + - Query responses by route and method |
| 59 | + - Generate capture statistics |
| 60 | + - Detect stale captures |
| 61 | + |
| 62 | +- **CaptureResponsesCommand**: Artisan command to run tests with capture enabled |
| 63 | + - Location: `src/Commands/CaptureResponsesCommand.php` |
| 64 | + - Command: `php artisan documentation:capture` |
| 65 | + - Options: `--clear`, `--stats` |
| 66 | + |
| 67 | +- **ValidateDocumentationCommand**: Command to validate documentation accuracy |
| 68 | + - Location: `src/Commands/ValidateDocumentationCommand.php` |
| 69 | + - Command: `php artisan documentation:validate` |
| 70 | + - Options: `--strict`, `--min-accuracy` |
| 71 | + |
| 72 | +- **DocumentationValidator**: Service for validating static vs captured data |
| 73 | + - Location: `src/Services/DocumentationValidator.php` |
| 74 | + |
| 75 | +#### Enhanced Response Analysis |
| 76 | + |
| 77 | +- **Shorthand Array Notation Support**: Added support for shorthand property definitions in `DataResponse` attributes |
| 78 | + - Format: `['type', nullable, 'description', 'example']` |
| 79 | + - Example: `['access_token' => ['string', null, 'Refreshed JWT token', 'ey**.***.***']]` |
| 80 | + - Location: `src/Services/EnhancedResponseAnalyzer.php:1303-1348` |
| 81 | + - Methods: `isShorthandPropertyDefinition()`, `parseShorthandPropertyDefinition()` |
| 82 | + |
| 83 | +- **Recursive Nested Property Schema Building**: Fixed nested object/array schema preservation in OpenAPI output |
| 84 | + - Location: `src/Services/OpenApi.php:580-634` |
| 85 | + - Method: `buildResponseSchema()` |
| 86 | + - Now recursively processes properties and items at any depth |
| 87 | + - Preserves format, nullable, required, enum fields |
| 88 | + |
| 89 | +- **Array Type Handling**: Added proper `items` schema for array types |
| 90 | + - Spatie Data DTOs with `array` type now include `items: {type: 'object'}` |
| 91 | + - Location: `src/Services/EnhancedResponseAnalyzer.php:827-830` |
| 92 | + |
| 93 | +- **DTO Type Introspection**: Enhanced type detection using DTO reflection |
| 94 | + - Extracts DTO class from PHPDoc comments (`@var ClassName $variable`) |
| 95 | + - Resolves fully qualified class names using `use` statements |
| 96 | + - Reflects on DTO properties to determine actual PHP types |
| 97 | + - Location: `src/Services/ResponseAnalyzer.php:1478-1513, 1662-1695` |
| 98 | + - Methods: `extractDtoClassFromMethodBody()`, `resolveClassNameWithUseStatements()`, `getPropertyTypeFromDto()` |
| 99 | + |
| 100 | +- **Property Name Heuristics**: Added intelligent fallback for common array property names |
| 101 | + - Properties named `meta`, `items`, `data`, `attributes`, `properties`, `tags`, `categories` automatically detected as arrays |
| 102 | + - Location: `src/Services/ResponseAnalyzer.php:1702-1705` |
| 103 | + |
| 104 | +### Fixed |
| 105 | + |
| 106 | +- **Wildcard Array Documentation**: Fixed issue where array validation rules with wildcard notation (e.g., `items.*`) were not properly documented |
| 107 | + - **Problem**: Fields like `'items.*' => ['string']` were documented as objects with a `*` property instead of arrays with items schema |
| 108 | + - **Root Cause**: The `transformParameter` method in `RouteComposition` didn't preserve `items` or `properties` schemas from `RequestAnalyzer` |
| 109 | + - **Solution**: Enhanced `transformParameter` to preserve three schema types: |
| 110 | + - `items`: For arrays (e.g., `items.*`) |
| 111 | + - `properties`: For nested objects (e.g., `wordpress.version`) |
| 112 | + - `parameters`: Legacy structure support |
| 113 | + - **Files Modified**: |
| 114 | + - `src/Services/RouteComposition.php:766-789` - Added items and properties preservation |
| 115 | + - `src/Services/RequestAnalyzer.php:1084-1140` - Enhanced wildcard detection for `items.*` |
| 116 | + - `src/Services/OpenApi.php:607-651` - Added items schema handling in request body builder |
| 117 | + - **Before**: `{"items": {"type": "array", "description": "..."}}` |
| 118 | + - **After**: `{"items": {"type": "array", "items": {"type": "string"}, "description": "..."}}` |
| 119 | + |
| 120 | +- **String vs Array Schema Handling**: Fixed issue where captured schemas with string property types (e.g., `"properties": "string"`) weren't handled correctly |
| 121 | + - Added type checking before recursive processing |
| 122 | + - Location: `src/Services/OpenApi.php:568-571, 581-584` |
| 123 | + |
| 124 | +- **Refresh Token Endpoint Schema**: Fixed incorrect schema where `access_token` appeared as object with numeric indices |
| 125 | + - Before: `{"access_token": {"0": "string", "1": "Unknown Type: mixed", ...}}` |
| 126 | + - After: `{"access_token": {"type": "string", "description": "Refreshed JWT token"}}` |
| 127 | + |
| 128 | +- **Property Name Regex**: Fixed regex pattern to match properties with trailing characters |
| 129 | + - Changed from `/\$[^->]+->(\w+)$/` to `/\$[^->]+->(\w+)/` |
| 130 | + - Now matches `$subscription->meta,` and `$subscription->meta;` patterns |
| 131 | + |
| 132 | +- **Nested Query Parameters**: Fixed issue where nested query parameters (e.g., `filter.service`) were not properly documented in GET requests |
| 133 | + - **Problem**: Validation rules like `'filter.service' => ['sometimes', 'string']` were documented as a single generic object parameter named `filter` |
| 134 | + - **Root Cause**: OpenApi builder didn't handle `properties` structure for GET request query parameters |
| 135 | + - **Solution**: Enhanced query parameter processing to expand nested objects into individual parameters using array notation |
| 136 | + - **Files Modified**: |
| 137 | + - `src/Services/OpenApi.php:284-341` - Added nested property expansion for query parameters |
| 138 | + - **Before**: Single parameter `filter` with `type: object` |
| 139 | + - **After**: Individual parameter `filter[service]` with `type: string` and full description |
| 140 | + - **Example Output**: |
| 141 | + ```json |
| 142 | + { |
| 143 | + "name": "filter[service]", |
| 144 | + "in": "query", |
| 145 | + "description": "Optional field that is validated only when present. Must be a string.", |
| 146 | + "required": false, |
| 147 | + "schema": { |
| 148 | + "type": "string" |
| 149 | + } |
| 150 | + } |
| 151 | + ``` |
| 152 | + |
| 153 | +### Changed |
| 154 | + |
| 155 | +#### Documentation Builder Enhancements |
| 156 | + |
| 157 | +- **Captured Response Integration**: DocumentationBuilder now merges static analysis with captured response data |
| 158 | + - Location: `src/Services/DocumentationBuilder.php:93-147` |
| 159 | + - Method: `enhanceRoutesWithCapturedData()` |
| 160 | + - Strategies: `captured_priority` (default), `static_priority`, `merge_both` |
| 161 | + - Config: `api-documentation.generation.merge_strategy` |
| 162 | + |
| 163 | +- **Response Format Conversion**: Added converter for captured response format to OpenAPI format |
| 164 | + - Location: `src/Services/DocumentationBuilder.php:149-177` |
| 165 | + - Method: `convertCapturedToOpenApiFormat()` |
| 166 | + - Properly extracts content-type from headers |
| 167 | + - Preserves examples, properties, items, required fields |
| 168 | + |
| 169 | +#### Configuration Updates |
| 170 | + |
| 171 | +- **Capture Configuration**: New config section for response capture |
| 172 | + - Location: `config/api-documentation.php` |
| 173 | + - Options: |
| 174 | + - `capture.enabled`: Enable/disable capture mode |
| 175 | + - `capture.storage_path`: Where to store captured responses |
| 176 | + - `capture.sanitize.sensitive_keys`: Keys to redact |
| 177 | + - `capture.rules.max_size`: Maximum response size to capture |
| 178 | + - `capture.rules.exclude_routes`: Routes to skip |
| 179 | + |
| 180 | +- **Generation Configuration**: New options for documentation generation |
| 181 | + - `generation.use_captured`: Enable captured response usage |
| 182 | + - `generation.merge_strategy`: How to merge static and captured data |
| 183 | + - `generation.fallback_to_static`: Fallback when no capture available |
| 184 | + - `generation.warn_missing_captures`: Log warnings for missing captures |
| 185 | + |
| 186 | +### Technical Details |
| 187 | + |
| 188 | +#### File Structure Changes |
| 189 | + |
| 190 | +``` |
| 191 | +src/ |
| 192 | +├── Commands/ |
| 193 | +│ ├── CaptureResponsesCommand.php (NEW) |
| 194 | +│ └── ValidateDocumentationCommand.php (NEW) |
| 195 | +├── Middleware/ |
| 196 | +│ └── CaptureApiResponseMiddleware.php (NEW) |
| 197 | +├── Services/ |
| 198 | +│ ├── CapturedResponseRepository.php (NEW) |
| 199 | +│ ├── DocumentationValidator.php (NEW) |
| 200 | +│ ├── DocumentationBuilder.php (MODIFIED) |
| 201 | +│ ├── EnhancedResponseAnalyzer.php (MODIFIED) |
| 202 | +│ ├── OpenApi.php (MODIFIED) |
| 203 | +│ └── ResponseAnalyzer.php (MODIFIED) |
| 204 | +└── LaravelApiDocumentationServiceProvider.php (MODIFIED) |
| 205 | +``` |
| 206 | +
|
| 207 | +#### Dependencies |
| 208 | +
|
| 209 | +- No new package dependencies added |
| 210 | +- Compatible with Laravel 10.x, 11.x, 12.x |
| 211 | +- PHP 8.0+ (uses `match` expressions) |
| 212 | +
|
| 213 | +## Workflow Integration |
| 214 | +
|
| 215 | +### Development Workflow |
| 216 | +
|
| 217 | +```bash |
| 218 | +# 1. Enable capture mode |
| 219 | +export DOC_CAPTURE_MODE=true |
| 220 | +
|
| 221 | +# 2. Run tests (captures responses automatically) |
| 222 | +composer test |
| 223 | +
|
| 224 | +# 3. Generate documentation (uses captured + static analysis) |
| 225 | +php artisan documentation:generate |
| 226 | +
|
| 227 | +# 4. Validate accuracy (optional) |
| 228 | +php artisan documentation:validate --min-accuracy=95 |
| 229 | +``` |
| 230 | + |
| 231 | +### Multi-Version Documentation |
| 232 | + |
| 233 | +The package now supports generating multiple documentation versions for different APIs: |
| 234 | + |
| 235 | +```php |
| 236 | +// config/api-documentation.php |
| 237 | +'files' => [ |
| 238 | + 'api' => [ |
| 239 | + 'name' => 'API Gateway Documentation', |
| 240 | + 'filename' => 'api-documentation.json', |
| 241 | + 'process' => true, |
| 242 | + ], |
| 243 | + 'public-api' => [ |
| 244 | + 'name' => 'Public API Documentation', |
| 245 | + 'filename' => 'public-api-documentation.json', |
| 246 | + 'process' => true, |
| 247 | + ], |
| 248 | +], |
| 249 | + |
| 250 | +'domains' => [ |
| 251 | + 'api' => [ |
| 252 | + 'title' => 'API Gateway Documentation', |
| 253 | + 'main' => env('APP_URL'), |
| 254 | + 'servers' => [...], |
| 255 | + ], |
| 256 | + 'public-api' => [ |
| 257 | + 'title' => 'Public API Documentation', |
| 258 | + 'main' => env('PUBLIC_API_URL'), |
| 259 | + 'servers' => [...], |
| 260 | + ], |
| 261 | +], |
| 262 | +``` |
| 263 | + |
| 264 | +### Controller Attribute Usage |
| 265 | + |
| 266 | +```php |
| 267 | +use JkBennemann\LaravelApiDocumentation\Attributes\DocumentationFile; |
| 268 | + |
| 269 | +#[DocumentationFile('public-api')] |
| 270 | +class PublicApiController extends Controller |
| 271 | +{ |
| 272 | + // Routes appear only in public-api-documentation.json |
| 273 | +} |
| 274 | +``` |
| 275 | + |
| 276 | +## Migration Notes |
| 277 | + |
| 278 | +### Breaking Changes |
| 279 | + |
| 280 | +None. All changes are backward compatible. |
| 281 | + |
| 282 | +### Deprecated Features |
| 283 | + |
| 284 | +None. |
| 285 | + |
| 286 | +### New Requirements |
| 287 | + |
| 288 | +- **Storage Symlink**: Ensure `php artisan storage:link` has been run for documentation files to be accessible via web |
| 289 | +- **Environment Variable**: Optionally set `DOC_CAPTURE_MODE=true` in `.env` for automatic capture during tests |
| 290 | + |
| 291 | +## Known Issues & Limitations |
| 292 | + |
| 293 | +### Static Analysis Limitations |
| 294 | + |
| 295 | +- **Array Type Detection**: Static analysis may incorrectly identify array fields as strings when: |
| 296 | + - DTO property types can't be resolved due to complex namespacing |
| 297 | + - Property access patterns don't match expected formats |
| 298 | + - **Solution**: Use runtime response capture for 100% accuracy |
| 299 | + |
| 300 | +### Workarounds |
| 301 | + |
| 302 | +1. **For Array Type Issues**: Run tests with `DOC_CAPTURE_MODE=true` to capture real response structures |
| 303 | +2. **For Missing Nested Properties**: Ensure PHPDoc comments include `@var` annotations in Resource `toArray()` methods |
| 304 | +3. **For Complex DTOs**: Add `#[Parameter]` attributes to DTO properties for explicit type hints |
| 305 | + |
| 306 | +## Performance Impact |
| 307 | + |
| 308 | +- **Zero Production Overhead**: Capture middleware only runs when `DOC_CAPTURE_MODE=true` and never in production |
| 309 | +- **Test Suite**: Minimal overhead (~50-100ms per test) when capture is enabled |
| 310 | +- **Documentation Generation**: Slight increase in generation time when processing captured responses |
| 311 | + |
| 312 | +## Security Considerations |
| 313 | + |
| 314 | +- **Sensitive Data Sanitization**: Automatic redaction of sensitive keys (passwords, tokens, secrets) |
| 315 | +- **Production Safety**: Multiple checks prevent capture from running in production |
| 316 | +- **File Permissions**: Captured response files are stored in `.schemas/` (should be gitignored for sensitive data) |
| 317 | + |
| 318 | +## Future Enhancements |
| 319 | + |
| 320 | +- [ ] PDF generation for commission statements |
| 321 | +- [ ] Email notifications for documentation updates |
| 322 | +- [ ] Advanced diff viewer for schema changes |
| 323 | +- [ ] Automatic validation in CI/CD pipelines |
| 324 | +- [ ] Integration with API testing tools |
| 325 | + |
| 326 | +--- |
| 327 | + |
| 328 | +**Full Documentation**: See implementation plan documents in `/docs/affiliate-system/` for detailed usage examples. |
| 329 | + |
| 330 | +**Contributors**: Jakob Bennemann, Claude Code |
| 331 | +**Date**: October 21, 2025 |
0 commit comments