tomatophp/tomato-api
A Laravel package from the TomatoPHP ecosystem that helps you build and manage RESTful APIs, providing ready-made endpoints and scaffolding to speed up backend development and integrate your TomatoPHP apps.
Architecture fit. The package is a Laravel service provider that publishes config and stubs and then generates resource controllers, form requests, API resources, and a repository interface plus Eloquent implementation, with Sanctum-backed token auth and versioned route prefixes. Fit is therefore narrow but legitimate: it pays off only where the team already writes Laravel with the repository pattern and wants conventional CRUD endpoints. Where the repository pattern isn't house style, the generated indirection is a permanent tax with no offsetting benefit — and that is an architecture-standard decision owned by a tech lead, not a side effect of a spike.
The critical framing for planning is that this is a code generator, not a runtime dependency. The durable artifact is the generated code and the templates, both of which survive dropping the package from require. That decouples adoption risk from runtime risk and is what makes an unmaintained package evaluable at all. It also means the architecture commitment (repository pattern, route conventions, resource shape) outlives the vendor relationship and must be approved as such.
Integration feasibility. Two gates, in order, both cheap:
illuminate/* constraints in the Laravel 9–10 band. composer why-not laravel/framework "^11.0" and a --dry-run install answer this in minutes. Non-resolution is a hard stop — everything after is a fork exercise, which is a different (and possibly still valid) decision.Also confirm the dependency tree in the dry run: TomatoPHP packages frequently pull in sibling packages (admin panel, roles/permissions). If installing a CRUD generator also adopts an ecosystem's auth and routing conventions, the commitment is materially larger than the description implies and should be re-scoped before approval.
Technical risk. Ranked by blast radius:
index/show may leak records across tenants; update/destroy may check authentication but not ownership. This reintroduces per resource and will not surface in a happy-path demo.$request->validated() straight through. If rules() leaks is_admin or tenant_id, a client can set it. Field-by-field review of rules() is required for the first several resources.Key questions to resolve before approval:
Stack fit and compatibility. Laravel 9–10 with Sanctum, HasApiTokens on the user model, and auth:sanctum in the middleware the config points at. Laravel 11+ requires php artisan install:api; on 9/10, publish Sanctum migrations manually. Budget for config and route publish collisions: if the app already has routes/api.php or a Sanctum config, diff what vendor:publish produced against what existed before, and check migration timestamp prefixes don't collide.
Migration path. Treat the package as a scaffold-and-extract tool. The intended end state is committed generated output living as ordinary application code, with the dependency optionally removed after the last resource is generated. Commit generated files as normal source, never regenerate in CI. Pin the version explicitly ("1.x", no caret) and record the fork decision in the README with a named owner.
Sequencing.
Category, Tag — never User or anything touching payments). Generate, then read five files in this order: routes (versioned? which middleware actually attached?), controller (repository injection or static model calls?), form requests (real rules or ['required'] placeholders?), repository implementation (paginated queries or Model::all()?), API resource (whitelisted fields or parent::toArray()?). That five-file read is the entire technical evaluation.authorize() or explicit policy binding in form requests, $fillable/$guarded on models, pagination defaults with a stable sort in the collection, rate-limit middleware on the route group, and the /api/v1/... prefix kept in place. This is the highest-leverage move available and the only thing that makes per-resource review cost amortize.RefreshDatabase feature test hitting all five verbs plus authorization failures, roughly 40 lines. This is the only regression net, since regeneration can overwrite files. Add an authz check to the PR template so every new resource is gated. Token issuance belongs in your app, not the generator: a small TokenController behind throttle:6,1, with explicit Sanctum abilities per token so read-only clients can't delete records. Use the generator as a comparison rather than a shortcut on anything with nested relations, computed fields, or non-trivial filtering.Maintenance. The team is the maintainer from day one. Required artifacts: pinned version, fork-or-reference decision documented, named owner, and a standing rule on regeneration — either generate once and never re-run for a resource, or customize stubs so hand-editing is never needed. Mixed strategies produce lost work. Expect a package-manager upgrade to be blocked at the Laravel major version boundary and plan the fork when that arrives.
Support. None. No vendor, no SLA, no documented upgrade path, no observable community to catch regressions. This is acceptable for internal, low-blast-radius workloads and disqualifying for production-critical or regulated paths until the code is fully owned.
Scaling — the key operational insight. The generator scales with model count, not with traffic. That produces two distinct cost curves that must be planned against:
Model::all(), every generated index endpoint is a latent memory and latency incident under real data volume — worth checking once at proof stage per repository, not per environment.Failure modes and mitigations.
| Failure mode | Signal | Mitigation |
|---|---|---|
| Silent authz gap | Records visible to wrong tenant/role | Policy check in PR template; authz assertions in each feature test |
| Mass assignment | Privileged field settable via payload | Field-by-field rules() review; explicit $fillable |
| Regeneration overwrite | Lost hand edits | Single agreed strategy; generated output treated as source |
| Route/name collision | Confusing 404s, stale behavior | php artisan route:list --path=api after every regeneration; one entry per verb per resource |
| Config publish collision | Overridden Sanctum or api.php config |
Diff publishables before committing |
| Ecosystem pull-in | Sibling TomatoPHP packages in tree | Read full --dry-run tree before install |
Ramp-up. Low for Laravel developers — it's conventional controllers, requests, and resources. Moderate for the repository-pattern convention if it isn't already house style; that onboarding cost is the hidden argument against adopting this package outside a TomatoPHP-aligned codebase.
Exit criteria, pre-agreed. Approve beyond the spike only if: constraint resolves on the target Laravel version, stubs are publishable, the single-model proof keeps at least two-thirds of generated output, the repository pattern is already house style, and an internal owner is named with a documented fork decision. If any of the first three fail, the correct outcome is a template lift, not a dependency.
How can I help you explore Laravel packages today?