zeusi/json-schema-extractor
Generate JSON Schema definitions directly from your Laravel/PHP code. This package extracts structured schemas for models, validation rules, and data shapes, making it easy to document APIs, power client-side validation, and keep schema definitions in sync with your application.
Architecture fit. The package addresses a real seam in Laravel API work: keeping machine-readable JSON Schema in sync with PHP DTOs without hand-maintaining a second source of truth. The "leverage existing metadata" premise is the right one — it implies reflection over typed properties, attributes, enums, and docblocks rather than a parallel annotation DSL, which is idiomatic for PHP 8.1+ codebases and aligns with how teams already write DTOs (readonly classes, promoted properties, backed enums) or with frameworks like spatie/laravel-data. If the extractor is truly pluggable ("modular"), it can be extended for our conventions (e.g., custom attributes for formats, examples, or vendor extensions) instead of forking. That is the strongest architectural argument for evaluating it.
Integration feasibility. Composer-distributed, MIT-licensed, and additive by nature — it reads DTOs and emits schemas, so it does not need to sit on the request path or wrap framework internals. That makes a trial cheap and reversible. The negatives are substantial though: 4 stars, 0 dependents, and no downstream projects validating it in the wild means we are effectively the first production user. There is also a provenance question worth resolving early: the package is published as zeusi/json-schema-extractor while the repository is under antonioturdo — we should confirm the Packagist entry maps to this source and that the release pipeline is trustworthy before pulling it into CI.
Technical risk. Ranked: (1) Silent correctness failure — a generated schema that is syntactically valid but semantically wrong (wrong nullability, missed required, collapsed unions, incorrect additionalProperties) is more dangerous than no schema, because downstream validators and generated clients will trust it; (2) coverage gaps — circular DTO graphs, $ref reuse, discriminated unions, DateTimeInterface, mixed, generics via phpdoc, and enum handling are where naive extractors break; (3) JSON Schema draft mismatch — OpenAPI 3.1 expects 2020-12, OpenAPI 3.0 expects a restricted subset, and we need to know which dialect the emitter targets; (4) bus factor — a single-maintainer package with a low release cadence and no visible test/CI signal; (5) version constraints — must confirm PHP and Laravel support windows before we design around it.
Key questions.
readonly properties, backed enums, nested DTOs, collections, nullable, union/intersection types) and spatie/laravel-data if we use it?$ref with $defs, or inline expansion?$id), so it can be committed and reviewed?TPM verdict: worth a time-boxed spike, not worth a committed dependency yet. Opportunity score 46 reflects genuine utility against very thin evidence of reliability.
Stack fit. Drop-in Composer dependency for a Laravel service. Expect no framework coupling beyond autoloading; if a service provider is shipped, registration is trivial. The natural insertion points are: a CI job that regenerates schemas from DTOs and fails on diff (drift detection), or a build step feeding an OpenAPI generator / client-code pipeline. It should stay out of the runtime request path — treat it as a build-time tool, not a library dependency of the application layer.
Migration path. Because it is additive, there is no migration in the breaking sense. Adopt in a branch, point it at one bounded domain's DTOs (the API surface with the most consumer pain), and diff its output against whatever exists today — hand-written schemas, OpenAPI YAML, or nothing. That diff is the real evaluation artifact: it tells us whether the tool's interpretation matches our intent before we invest further.
Compatibility. Three axes to verify explicitly: PHP version constraint vs. our runtime, Laravel version vs. our LTS cadence, and DTO framework vs. our chosen conventions. If we use spatie/laravel-data, confirm the extractor reads its metadata or can be extended to; if we use plain DTOs, confirm attribute support. Also confirm the emitted schema dialect is consumable by our actual downstream tools (Stoplight, Swagger UI, openapi-generator, Ajv) — a 2020-12 emitter is useless to a strict OpenAPI 3.0 consumer.
Sequencing.
required, nullability, and $ref behavior.Effort estimate: 1 engineer-day for the spike and gate, ~1 sprint for the pilot, with a documented abort point after step 3.
Maintenance. This is the dominant cost. A 4-star, 0-dependent package means we will own the maintenance burden, not share it. Mitigations: pin an exact version (no caret ranges) with a locked composer.lock, isolate all calls behind one internal adapter class so the tool can be swapped for a fork or a competitor (symfony/serializer + a schema generator, or hand-authored schemas) without touching call sites, and be prepared to vendor the source. Budget a standing fraction of an engineer to track upstream and re-validate on each PHP/Laravel upgrade. The provenance mismatch (Packagist name vs. GitHub org) should be resolved before adoption — if it can't be, treat it as a supply-chain blocker.
Support. No commercial support, no SLA, no guarantee of issue response. We need an internal owner, a written behavior contract captured as golden-file tests, and a documented list of known-unsupported DTO shapes so engineers don't silently get bad output. Ramp-up for a new engineer is low if the public API is a single "generate from class" call; higher if they must author custom extractors, which requires reading source.
Scaling. Effectively free — this is a build-time codegen concern, not a runtime one. The scaling dimension is DTO graph size: schema output grows with the object graph, circular references must be $ref'd rather than expanded, and generation time on a large domain (hundreds of DTOs) should be measured. Cache generated schemas as build artifacts and commit them so review diffs surface contract changes.
Failure modes. Enumerate them for on-call: (a) schema silently diverges from runtime DTO after a refactor — mitigated by a blocking CI diff; (b) upstream minor release changes output format — mitigated by exact pinning; (c) unhandled PHP construct causes a fatal during generation — mitigated by running generation in CI, not at deploy; (d) generated schema validates but is semantically weaker than intended (e.g., everything optional) — mitigated by hand-review of the pilot output, not just green validation; (e) abandoned upstream — mitigated by the adapter boundary and a fork playbook.
Ramp-up. Low for consumers (read the emitted JSON), moderate for owners (understand the extractor pipeline and extension points). Plan a half-day knowledge transfer and a short internal README documenting: how to run generation, where schemas live, how to add a custom extractor, and the escalation path if upstream is unresponsive.
Recommendation. Proceed to a time-boxed spike with a hard abort gate after the extension probe. Do not adopt as a load-bearing dependency until it has survived two sprints of CI drift-checking with zero semantic incidents and we have confirmed the release provenance and maintenance posture.
How can I help you explore Laravel packages today?