genai/openapi

Generates an OpenAPI 3 document at build time from your #[RestController] routes, request-body Forms/DTOs and validation constraints — baked into a reflection-free Cache\OpenApi — and ships a controller that serves /openapi.json and a Swagger UI page at /docs. PHP 5.3-safe at runtime.

Maintainers

Package info

github.com/GenAIIO/php-openapi

pkg:composer/genai/openapi

Transparency log

Statistics

Installs: 24

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.1 2026-07-10 02:09 UTC

This package is auto-updated.

Last update: 2026-07-10 02:14:19 UTC


README

Auto-generates an OpenAPI 3 document for your JSON API and serves Swagger UI — the same compile-time-scan approach as the rest of the stack, so the docs come for free with zero runtime cost.

How it works

A build processor (OpenApiProcessor) runs during composer compile and reads the attributes you already have:

  • Paths + methods#[Route] / #[GetMapping] / #[PostMapping] … on #[RestController] classes (HTML #[Controller]s are ignored — they're not an API).
  • Path params{braces} in the route path.
  • Request body schema ← an action's GenAI\Web\Form parameter → a component schema built from that class's fields.
  • Schemas ← a #[Dto] is described by its getters and their return types (matching how the serializer emits it; nested DTOs become $refs). A request Form is described by its properties + validation constraints (anything exposing rule()): #[NotBlank]required, #[Email]format: email, #[Length(min/max)]minLength/maxLength, #[Pattern]pattern.
  • Summary / description ← optional args on the mapping itself (#[GetMapping('/games', summary: '…', description: '…')]).
  • Tag (groups endpoints) ← #[RestController(tag: '…', description: '…')].

The document is baked into Cache\OpenApi::json() (always emitted), and a shipped controller exposes it:

  • GET /openapi.json — the spec
  • GET /docs — Swagger UI (loads swagger-ui-dist from a CDN → needs internet)

Use it

composer require genai/openapi
composer compile

Then annotate a JSON endpoint:

#[RestController(path: '/api', tag: 'KidSafe API', description: 'Public JSON endpoints.')]
class ApiController
{
    #[GetMapping('/games', summary: 'List the published games')]
    public function games() { return $this->games->all(); }       // RestController -> JSON

    #[PostMapping('/feedback', summary: 'Send feedback')]
    public function feedback(FeedbackForm $form) { ... }           // body schema from FeedbackForm
}

Open …/docs to explore. …/openapi.json is the raw document (feed it to client generators, Postman, etc.).

Notes

  • Build-time, zero runtime cost — the spec is baked, like Cache\Router.

  • REST only#[Controller] (HTML/view) actions are intentionally excluded.

  • Success response: point the mapping at a response DTO — #[GetMapping('/games', response: GameView::class . '[]')] (append [] for an array). The DTO is a plain documentation class; field types come from @var docblocks (props can't be typed on PHP 5.3). If no response: is given, the processor reads a declared return type (: array, : GameView) — but that's PHP 7+ syntax that breaks a 5.3 runtime, so on 5.3 use response:. Otherwise a generic 200.

  • Error responses: list the statuses on the mapping with errorCodes: [...] (validated at compile time — a value outside 100–599 fails the build). Each is documented with the one shared Error component ({ code, message }), so every error in the API looks the same; the description is the standard HTTP reason phrase. Example:

    #[PostMapping('/feedback', summary: 'Send feedback', response: FeedbackResult::class, errorCodes: [422, 500])]
    public function feedback(FeedbackForm $form) { ... }
  • Decoupled — validation facets are read by duck-typing rule(), so it works with or without genai/validation installed.

  • Swagger UI is loaded from a CDN for convenience; for an offline/CSP setup, vendor swagger-ui-dist and point the /docs page at the local assets.