php-openapi/openapi
PHP library for reading, validating, and writing OpenAPI 3.0 specifications. Parse JSON or YAML into an object model, resolve references, inspect paths and schemas, and generate updated spec files—useful for API tooling, docs, and governance.
Architecture fit. This is a single-purpose model layer: it parses OpenAPI 3.x documents (JSON/YAML) into a typed object graph (OpenApi\Annotations\*), resolves $refs, and serializes back out. It is framework-agnostic — no service provider, no facade, no config file — which is the right shape for a Laravel codebase because it introduces no framework coupling and no upgrade pressure tied to Laravel majors. The fit question is not "is it good code," it's "is this the right direction of data flow." This package consumes OpenAPI documents. If the product requirement is "generate an OpenAPI spec from our Laravel routes and controllers," this is the wrong tool (that's zircote/swagger-php or dedoc/scramble). If the requirement is "read a spec — ours, a partner's, a customer's — and act on it" for contract testing, gateway/route config generation, SDK or mock scaffolding, or documentation publishing, it is precisely the right primitive.
Integration feasibility. High. Composer install, no native extensions beyond ext-json, no database, no daemon, no long-running process. The dependency surface is thin (symfony/yaml only if YAML is needed, psr/log optional). A working read → inspect → serialize path is an afternoon of work. The genuine effort is downstream of installation: defining what we do with the object graph, hardening against untrusted input, and caching parsed results so nothing re-parses per request. Teams routinely under-scope that second half and over-scope the install.
Technical risk. Four items, in descending order of importance:
league/openapi-psr7-validator. The most likely explanation is a repository/namespace migration (this is the continuation of cebe/php-openapi) where GitHub metrics did not follow the redirect. That is probably benign — but "probably" is not an adoption rationale. Verify the redirect chain, confirm the maintainer continuity, and check that Packagist downloads and issue activity match a healthy project before committing.nullable/type semantics materially. Support status is the difference between a viable long-term dependency and a rewrite in 18 months. Spike it; do not trust a README badge.$ref resolution triggering outbound HTTP (SSRF), deep nesting causing memory exhaustion. Treat every external spec as hostile input from day one.Key questions.
swagger-php immediately.)$ref fetch policy are launch requirements, not follow-ups.league/openapi-psr7-validator enters the dependency picture and should be evaluated in the same decision, not later.cebe/php-openapi, and are the star/dependent counts post-migration artifacts?Stack fit. Composer, PSR-4, zero Laravel coupling — it will install cleanly and behave identically in an artisan command, a queued job, or an HTTP request. The architectural guidance is to wrap it: a single OpenApiDocumentService or SpecRepository in the application layer that owns read, cache, and ref-resolution policy. Do not let OpenApi\Reader::readFromJsonFile() calls proliferate through controllers. A one-class seam keeps the replacement cost at days instead of quarters if upstream stalls, and it gives you one place to enforce the security policy.
Migration path. Two realistic starting points:
cebe/php-openapi: near drop-in — same OpenApi\ namespace lineage. Expect import churn and behavioral differences in reference resolution rather than API redesign. Budget roughly a day for a mid-size codebase plus a regression pass on $ref-heavy specs.json_decode array walking: the more common starting state. Migrate one consumer at a time — documentation pipeline first, then mock server or config generation — running old and new paths in parallel and diffing outputs. The typed graph will surface assumptions the array code silently made.swagger-php, that is not a migration; it solves the inverse problem. Don't let the two get conflated in scoping.Compatibility. Check the package's PHP floor against our Laravel version's floor and our CI matrix — the intersection frequently forces an upgrade decision nobody budgeted for. Run composer why-not early; symfony/yaml constraints are the usual conflict point with Laravel's transitive graph. Treat 3.0 and 3.1 as a semantic fork and build a fixture suite covering both. Finally, $ref resolution modes (inline-expand vs. preserve) change the shape of the object graph, and downstream code will silently depend on whichever you pick — codify the choice in the adapter and document it.
Sequencing. Roughly four to six weeks for a mid-size team:
Maintenance. Low steady state. No runtime services, no schema migrations, no workers to babysit. The recurring cost is upgrade churn: the OpenAPI specification evolves, and pinning a major version means someone has to track releases and PHP-version support. The risk with a small contributor base is not a dramatic break — it's quiet decay. Assign a named owner and put a quarterly review on the calendar: latest release, supported PHP versions, open-issue trend, unresolved security-adjacent issues.
Support. MIT, community-only, no commercial backing or SLA. Escalation is GitHub issues plus, ultimately, our own fork. That is acceptable for internal tooling and documentation pipelines. It is a real gap for anything on a customer-facing critical path — if we end up validating inbound API traffic with the sibling validator, budget contingency for an internal fork or a maintainer engagement, and do not place it in a tier-1 latency-critical path without a fallback.
Scaling. Parsing is CPU- and memory-bound and scales with document size, not request volume. Multi-megabyte specs with hundreds of paths can consume tens to hundreds of megabytes; a fully inlined, $ref-expanded graph is materially worse than a preserved one. The mitigation is architectural, not the library's responsibility: parse once, cache the artifact, never parse per request. For memory-sensitive jobs, prefer preserve-ref mode and resolve on demand. If tenant-supplied specs ever enter the picture, isolate parsing in a dedicated queue worker with hard memory and time limits.
Failure modes to design for.
$ref → parse exception at best, outbound HTTP request at worst. Disable remote resolution by default; allowlist if truly unavoidable.nullable/type. Reject unknown versions loudly.Ramp-up. A competent PHP engineer is productive with the read/serialize path in a day; the generated object model is verbose but predictable. The real ramp-up cost is OpenAPI literacy, not the library — engineers need working fluency in $ref, components, and 3.0-vs-3.1 semantics to use the graph correctly, and that's a week, not a day. Mitigate with a short internal README covering the adapter contract, the ref-resolution policy, the caching pattern, and the security guardrails. That document is what stops the next engineer from re-parsing specs inside a controller.
How can I help you explore Laravel packages today?