wwwision/types-openapi

Generator for OpenAPI schema files, see https://www.openapis.org/

Maintainers

👁 bwaidelich

Package info

github.com/bwaidelich/types-openapi

pkg:composer/wwwision/types-openapi

Fund package maintenance!

bwaidelich

Paypal

Statistics

Installs: 6 950

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

2.2.1 2026-01-15 16:07 UTC

Suggests

None

Provides

None

Conflicts

None

Replaces

None

MIT 98e7eb868a9d6d5d26012935b6040a9acda7ac28

  • bwaidelich <b.waidelich.woop@wwwision.de>

This package is auto-updated.

Last update: 2026-06-15 17:07:30 UTC


README

...possibly... ;)

Integration for the wwwision/types package that allows for generation of OpenAPI schemas and APIs from PHP code

Usage

This package can be installed via composer:

composer require wwwision/types-openapi

Simple Example

This is all that is required to generate an OpenAPI schema for a simple HTTP endpoint:

final class SomeApi {

 #[Operation(path: '/', method: 'GET')]
 public function someEndpoint(): string {
 return '{"success":true}';
 }
}

$openApiObject = (new OpenApiGenerator())->generate(SomeApi::class);

assert($openApiObject instanceof OpenApiObject);
$expectedSchema = <<<JSON
{"openapi":"3.0.3","info":{"title":"","version":"0.0.0"},"paths":{"\/":{"get":{"operationId":"someEndpoint","responses":{"200":{"description":"Default","content":{"application\/json":{"schema":{"type":"string"}}}}}}}}}
JSON;
assert(json_encode($openApiObject) === $expectedSchema);

Serve HTTP Requests

This package comes with a RequestHandler that allows for serving HTTP requests using the generated OpenAPI schema. The RequestHandler is PSR-7 compatible such that it can easily be integrated with a corresponding psr/http-factory/psr/http-message provider, e.g. guzzlehttp/psr7:

// ... 

$api = new SomeApi();
$httpFactory = new HttpFactory();
$requestHandler = new RequestHandler($api, $httpFactory, $httpFactory);

$request = ServerRequest::fromGlobals();
try {
 $response = $requestHandler($request);
} catch (RequestException $e) {
 $response = $httpFactory->createResponse($e::getStatusCode(), $e::getReasonPhrase());
 $response->getBody()->write($e->getMessage());
}
http_response_code($response->getStatusCode());
foreach ($response->getHeaders() as $k => $values) {
 foreach ($values as $v) {
 header(sprintf('%s: %s', $k, $v), false);
 }
}
echo $response->getBody();

Parameters

Arguments of the endpoint methods are automatically mapped to OpenAPI parameters. All OpenAPI parameter types are supported (query, path, header, cookie).

Query parameters

By default, the parameter type is query:

final class SomeApi {

 #[Operation(path: '/', method: 'GET')]
 public function someEndpoint(string $someParam, string|null $someOptionalParam = null): string {
 return $someParam;
 }
}

will accept requests like

GET /?someParam=foo HTTP/1.1

and

GET /?someParam=foo&someOptionalParam=bar HTTP/1.1

and will map the values to the corresponding method arguments.

Path parameters

Operations can also make use of Path Templating in order to map method arguments from the query path:

final class SomeApi {

 #[Operation(path: '/static/{param1}/{param2}', method: 'GET')]
 public function someEndpoint(string $param1, string $param2): string {
 // ...
 }
}

Path params cannot be optional and must be defined in the path template.

Header parameters

To define a header parameter, the #[Parameter] attribute can be used:

final class SomeApi {

 #[Operation(path: '/', method: 'GET')]
 public function someEndpoint(#[Parameter(in: ParameterLocation::header, name: "X-HeaderName")] string $paramFromHeader): string {
 // ...
 }
}

Cookie parameters

Likewise, to define a cookie parameter, the #[Parameter] attribute can be used:

final class SomeApi {

 #[Operation(path: '/', method: 'GET')]
 public function someEndpoint(#[Parameter(in: ParameterLocation::cookie, name: "CookieName")] string $paramFromCookie): string {
 // ...
 }
}

Complex types

Complex parameter types are supported as well as long as they follow the wwwision/types best practices:

#[StringBased(minLength: 3)]
final readonly class Username {
 private function __construct(
 public string $value,
 ) {}
}

final class SomeApi {

 #[Operation(path: '/', method: 'GET')]
 public function someEndpoint(Username $username): string {
 return $username->value;
 }
}

This will validate and map the parameter and fail if it does not satisfy the constraints:

{
 "type": "https://www.rfc-editor.org/rfc/rfc9110#name-400-bad-request",
 "title": "Bad Request",
 "issues": [
 {
 "code": "too_small",
 "message": "String must contain at least 3 character(s)",
 "path": [
 "query.username"
 ],
 "type": "string",
 "minimum": 3,
 "inclusive": true,
 "exact": false
 }
 ]
}

Example

The following example makes use of all parameter types:

final class SomeApi {

 #[Operation(path: '/{paramFromPath}', method: 'GET')]
 public function someEndpoint(
 string $paramFromPath,
 #[Parameter(in: ParameterLocation::header, name: "X-Foo")]
 string $paramFromHeader,
 #[Parameter(in: ParameterLocation::cookie, name: "SomeCookie")]
 string $paramFromCookie,
 string $paramFromQuery,
 ): string {
 return json_encode(func_get_args());
 }
}

This will lead to an OpenAPI definition like this:

{
 // ...
 "paths": {
 "/{paramFromPath}": {
 "get": {
 "operationId": "someEndpoint",
 "parameters": [
 {
 "name": "paramFromPath",
 "in": "path",
 "required": true,
 "schema": {
 "type": "string"
 }
 },
 {
 "name": "X-Foo",
 "in": "header",
 "required": true,
 "schema": {
 "type": "string"
 }
 },
 {
 "name": "SomeCookie",
 "in": "cookie",
 "required": true,
 "schema": {
 "type": "string"
 }
 },
 {
 "name": "paramFromQuery",
 "in": "query",
 "required": true,
 "schema": {
 "type": "string"
 }
 }
 ],
 // ...
 }
 }
 }
}

And an HTTP request like:

GET /valueFromPath?paramFromQuery=valueFromQuery HTTP/1.1
Host: localhost:8000
X-Foo: valueFromHeader
Cookie: SomeCookie=valueFromCookie

...will result in the following response:

["valueFromPath","valueFromHeader","valueFromCookie","valueFromQuery"]

Security

To implement custom authentication schemes, you can implement the AuthenticationContextProvider interface and return an instance of your custom AuthenticationContext class:

final class CustomAuthContext implements AuthenticationContext {
 public function __construct(
 public readonly string|null $authenticatedUserId,
 ) {
 }
}

final class AuthContextProvider implements AuthenticationContextProvider {
 public function getAuthenticationContext(ServerRequestInterface $request, SecurityRequirementObject $securityRequirement): CustomAuthContext|null {
 // TODO: evaluate the request and security requirement
 return new CustomAuthContext(authenticatedUserId: 'john.doe');
 }
}

The AuthenticationContext is passed to the endpoint method as an additional argument, if the security option of the Operation attribute is set. The RequestHandler will automatically call the getAuthenticationContext() method of your provider and pass the result to the endpoint method. Security schemes can be defined using the #[OpenApi] attribute:

// ...

#[OpenApi(
 // ...
 securitySchemes: [
 'someSchema' => [
 'type' => 'http',
 'scheme' => 'bearer',
 ],
 ],
)]
final class SomeApi {

 #[Operation(path: '/', method: 'POST', security: 'someSchema')]
 public function securedEndpoint(CustomAuthContext $authContext): CreatedResponse
 {
 if ($authContext->authenticatedUserId !== 'john.doe') {
 return new UnauthorizedResponse();
 }
 // do something
 return new CreatedResponse();
 }
}

More Examples

Contribution

Contributions in the form of issues or pull requests are highly appreciated

License

See LICENSE