Problem Statement
Currently, to add response descriptions to the OpenAPI spec, you must call addResponse() programmatically in the constructor. There is no declarative annotation-based approach, which is inconsistent with the rest of the annotation-driven API design (#[GetMapping], #[RequestParam], #[ResponseBody], etc.).
Proposed Solution
Add a repeatable #[ApiResponse] attribute that can be placed on service methods:
#[GetMapping]
#[ResponseBody]
#[ApiResponse(status: '200', description: 'List of products or a single product')]
#[ApiResponse(status: '404', description: 'Product not found')]
public function getProducts(): array {
// ...
}
Implementation:
- Create
WebFiori\Http\Annotations\ApiResponse:
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class ApiResponse {
public function __construct(
public string $status = '200',
public string $description = '',
) {}
}
-
In WebService::toPathItemObj(), read #[ApiResponse] attributes from the mapped method and build the ResponsesObj from them instead of the default "200" => "Successful operation" fallback.
-
If addResponse() was called programmatically, those take priority over annotations.
Alternatives Considered
- Using doc-block annotations (rejected — framework uses PHP 8 attributes exclusively)
- Class-level annotation (rejected — ambiguous for services with multiple HTTP methods)
Breaking Change
No
Additional Context
This came up while building the blog example for the OpenAPI/Swagger documentation post. The current workaround is calling addResponse() in the constructor, which works but breaks the declarative pattern.
Problem Statement
Currently, to add response descriptions to the OpenAPI spec, you must call
addResponse()programmatically in the constructor. There is no declarative annotation-based approach, which is inconsistent with the rest of the annotation-driven API design (#[GetMapping],#[RequestParam],#[ResponseBody], etc.).Proposed Solution
Add a repeatable
#[ApiResponse]attribute that can be placed on service methods:Implementation:
WebFiori\Http\Annotations\ApiResponse:In
WebService::toPathItemObj(), read#[ApiResponse]attributes from the mapped method and build theResponsesObjfrom them instead of the default"200" => "Successful operation"fallback.If
addResponse()was called programmatically, those take priority over annotations.Alternatives Considered
Breaking Change
No
Additional Context
This came up while building the blog example for the OpenAPI/Swagger documentation post. The current workaround is calling
addResponse()in the constructor, which works but breaks the declarative pattern.