Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Openapi Laravel Package

psx/openapi

Generate OpenAPI specification documents for your PHP REST API. Part of the PSX framework, this component helps describe endpoints, parameters, and schemas so your API can be documented and consumed by standard OpenAPI tooling.

View on GitHub
Deep Wiki
Context7

Getting Started

psx/openapi provides a set of PHP model classes that mirror the OpenAPI 3.x object graph (OpenAPI, Info, Paths, PathItem, Operation, Responses, Schema, Components, etc.). You construct the object tree in code and serialize it to JSON — the package is a builder, not a validator or a code generator.

  1. Install:

    composer require psx/openapi
    

    It pulls in psx/record / psx/schema (the model base and (de)serialization layer), so most instances are JsonSerializable.

  2. Look first at PSX\OpenAPI\OpenAPI — this is the root object and its constructor/properties tell you the full shape of the document (openapi, info, servers, paths, components, tags, security, externalDocs). Then open Operation, Response, and Schema; those three carry most of the day-to-day work.

  3. Minimal first use case — emit a static spec:

    <?php
    use PSX\OpenAPI\OpenAPI;
    use PSX\OpenAPI\Info;
    use PSX\OpenAPI\Paths;
    use PSX\OpenAPI\PathItem;
    use PSX\OpenAPI\Operation;
    use PSX\OpenAPI\Response;
    use PSX\OpenAPI\Responses;
    
    $spec = new OpenAPI(
        openapi: '3.0.3',
        info: new Info(title: 'My API', version: '1.0.0'),
        paths: new Paths([
            '/health' => new PathItem(
                get: new Operation(
                    operationId: 'getHealth',
                    summary: 'Health check',
                    responses: new Responses([
                        '200' => new Response(description: 'OK'),
                    ]),
                ),
            ),
        ]),
    );
    
    file_put_contents('openapi.json', json_encode($spec, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
    

    (Constructor argument names/order vary by generated model — use named arguments where the model supports them, and verify against the class source.)

  4. Serve it from a route (e.g. GET /openapi.json) so tooling (Swagger UI, Postman, Redoc) can always pull the live definition.

Implementation Patterns

Code-first generation from route/controller metadata. The most valuable pattern is to define your endpoints once (attributes, config, or a controller registry) and have a builder translate that into PathItem/Operation objects. This keeps the spec in sync with the code that actually serves traffic, which is the whole reason to own a type-safe builder instead of hand-editing YAML.

Compose, don't inline. OpenAPI documents are usually 80% $ref. Build each schema once inside Components.schemas and reference it:

$userSchema = new Schema(type: 'object', properties: [
    'id'   => new Schema(type: 'integer'),
    'name' => new Schema(type: 'string'),
]);
$ref = new Schema(ref: '#/components/schemas/User');

Use the same object (or a shared $ref Schema) in MediaType.schema for request and response bodies. This is where the type-safety pays off — a typo costs you a PHP error, not a broken tooling import.

Separate "describe a schema" from "describe an operation." Create a small helper that maps your domain type (DTO, entity, JSON-Schema-ish array) into a Schema. Then a second helper turns a route + input type + output type into an Operation. Each helper is independently testable and reusable across endpoints.

Build at deploy time, serve at runtime. Generate the spec in a console command / CI step and store openapi.json as an artifact. Runtime generation is fine for small APIs but couples your /openapi.json endpoint to every model class being loadable; build-time keeps p95 latency for that endpoint at zero.

Interop with psx/api. If you are already in the PSX ecosystem, psx/api's OpenAPI parser round-trips through these model classes — meaning you can parse an existing openapi.yaml into this object graph, mutate it (add servers, patch a path), and re-emit. That's a clean way to layer organization-specific conventions onto an upstream spec.

Parameterize by environment. Keep Info and Components static, but inject Server entries per environment (local, staging, prod). This gives you one spec template and N published documents without branching inside path definitions.

Gotchas and Tips

  • Constructor order is positional and long. Operation, PathItem, and Schema have many arguments; a swapped pair compiles but silently produces a wrong spec. Prefer named arguments (PHP 8+) or the setter/property API where available, and add a snapshot test that asserts the JSON output.
  • Required fields are not enforced by the model. The OpenAPI spec requires info.title, info.version, every Response.description, and every Operation.responses. The models happily accept null; your tooling will not. Validate after building.
  • Paths and Responses are string-keyed maps. '/users/{id}' and '200' are keys, not objects. Status-code ranges like '2XX' and 'default' are valid keys — treat them as strings, not ints.
  • $ref strings are not checked. #/components/schemas/User must exactly match a key under Components.schemas. There is no static analysis here; a broken ref surfaces only when Swagger UI fails to render.
  • Null vs. empty array matters. An empty parameters: [] and parameters: null serialize differently and some tooling treats null as "missing" and [] as "explicitly none." Decide per field and be consistent; JSON_UNESCAPED_SLASHES also affects $ref readability.
  • OpenAPI 3.0 vs 3.1. The model tracks 3.0 semantics (nullable: true, example); 3.1 uses JSON-Schema-style type: ['string', 'null'] and examples. If your consumers are on 3.1, expect to post-process the output rather than rely on the models to express it.
  • No built-in serialization to YAML. The models JSON-encode; if your consumers need openapi.yaml, add symfony/yaml or psx/yaml and convert the decoded array. Do the round-trip through json_decode(json_encode($spec), true) — that is your safe normalization step.
  • No validation. Pair the output with a validator in CI (cebe/php-openapi, stoplight/spectral, or Redoc's linter). This is the single highest-leverage addition — it catches required-field and ref errors the model layer will never flag.
  • Debugging large specs. json_encode($spec, JSON_PRETTY_PRINT) into a file, then diff against the previous build in CI. Snapshot diffs catch accidental structural regressions far better than eyeballing.
  • Small package, thin bus factor (2 stars upstream). Pin an exact version in composer.json, vendor the source if you rely on a specific field mapping, and keep your builder logic in your own service class rather than spread across the model constructors — that way you can swap the underlying package without rewriting call sites.
  • Extension points. OpenAPI allows x-* vendor extensions. Check whether the base Record/model accepts arbitrary extra keys (e.g. via Record's dynamic properties) — if it does, use x- keys for internal hints (routing, auth scopes) instead of forking the models.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource