fix(api-docs): deduplicate explicit OpenAPI parameters
Explicit ApiParameter metadata now replaces matching auto-generated path parameters instead of producing duplicates, matching the precedence used by the Go OpenAPI builder. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
a89a70851f
commit
929b6b97ca
2 changed files with 57 additions and 4 deletions
|
|
@ -523,16 +523,36 @@ class OpenApiBuilder
|
|||
protected function buildParameters(Route $route, ?object $controller, string $action, array $config): array
|
||||
{
|
||||
$parameters = [];
|
||||
$parameterIndex = [];
|
||||
|
||||
$addParameter = function (array $parameter) use (&$parameters, &$parameterIndex): void {
|
||||
$name = $parameter['name'] ?? null;
|
||||
$in = $parameter['in'] ?? null;
|
||||
|
||||
if (! is_string($name) || $name === '' || ! is_string($in) || $in === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$key = $in.':'.$name;
|
||||
if (isset($parameterIndex[$key])) {
|
||||
$parameters[$parameterIndex[$key]] = $parameter;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$parameterIndex[$key] = count($parameters);
|
||||
$parameters[] = $parameter;
|
||||
};
|
||||
|
||||
// Add path parameters
|
||||
preg_match_all('/\{([^}?]+)\??}/', $route->uri(), $matches);
|
||||
foreach ($matches[1] as $param) {
|
||||
$parameters[] = [
|
||||
$addParameter([
|
||||
'name' => $param,
|
||||
'in' => 'path',
|
||||
'required' => true,
|
||||
'schema' => ['type' => 'string'],
|
||||
];
|
||||
]);
|
||||
}
|
||||
|
||||
// Add parameters from ApiParameter attributes
|
||||
|
|
@ -544,12 +564,12 @@ class OpenApiBuilder
|
|||
|
||||
foreach ($paramAttrs as $attr) {
|
||||
$param = $attr->newInstance();
|
||||
$parameters[] = $param->toOpenApi();
|
||||
$addParameter($param->toOpenApi());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
return array_values($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -245,6 +245,29 @@ describe('Application Endpoint Parameter Docs', function () {
|
|||
expect($serverIncludeContent['schema']['type'])->toBe('boolean');
|
||||
});
|
||||
|
||||
it('lets explicit path parameter metadata override the generated entry', function () {
|
||||
RouteFacade::prefix('api')
|
||||
->middleware('api')
|
||||
->group(function () {
|
||||
RouteFacade::get('/test-scan/items/{id}/explicit', [TestExplicitPathParameterController::class, 'show']);
|
||||
});
|
||||
|
||||
$builder = new OpenApiBuilder;
|
||||
$spec = $builder->build();
|
||||
|
||||
$operation = $spec['paths']['/api/test-scan/items/{id}/explicit']['get'];
|
||||
$parameters = $operation['parameters'] ?? [];
|
||||
|
||||
expect($parameters)->toHaveCount(1);
|
||||
|
||||
$idParam = collect($parameters)->firstWhere('name', 'id');
|
||||
|
||||
expect($idParam)->not->toBeNull();
|
||||
expect($idParam['in'])->toBe('path');
|
||||
expect($idParam['required'])->toBeTrue();
|
||||
expect($idParam['description'])->toBe('Explicit item identifier');
|
||||
});
|
||||
|
||||
it('documents the MCP tool call request body shape', function () {
|
||||
$builder = new OpenApiBuilder;
|
||||
$spec = $builder->build();
|
||||
|
|
@ -1178,6 +1201,16 @@ class TestPartialHiddenController
|
|||
public function hiddenMethod(): void {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test controller with an explicit path parameter override.
|
||||
*/
|
||||
class TestExplicitPathParameterController
|
||||
{
|
||||
#[ApiParameter('id', 'path', 'string', 'Explicit item identifier')]
|
||||
#[ApiResponse(200, TestJsonResource::class, 'Item details')]
|
||||
public function show(string $id): void {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test tagged controller.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue