gollumsf/rest-bundle
gollumsf/rest-bundle is a Symfony bundle for building RESTful APIs with less boilerplate. It helps configure resource endpoints, handle requests, serialize responses, and keep JSON API output consistent across services.
type: symfony-bundle), not a Laravel package. It has no service provider, no facade, and nothing to publish. composer require gollumsf/rest-bundle may resolve dependencies inside a Laravel app, but the bundle's boot logic only runs through a Symfony Kernel — in Laravel it is inert.composer.json (type + require block), the bundle/extension class in src/ (that's the real entry point), the README for the attribute/annotation syntax, docs/Sorting.md (the most useful reference — see below), and the LICENSE file. The license matters more than the API surface here.routes/api.php + Route::apiResource, a FormRequest, a JsonResource, and a JSON error renderer in bootstrap/app.php via withExceptions. That covers the bulk of what a small REST bundle provides.The bundle's model — thin actions, framework-handled deserialization/serialization, standardized error payloads, server-driven sort/paginate — maps cleanly onto Laravel primitives:
| Bundle concept | Laravel equivalent |
|---|---|
| Single-action REST controller | Invokable controller or one route per action |
| Request body deserialization | FormRequest (validation + authorize) with a toDto() method, or spatie/laravel-data for attribute-driven mapping |
| Response serialization | JsonResource / ResourceCollection — never return Eloquent models raw |
| Error envelope | withExceptions() / render() forcing {error: {code, message, details}} for API routes |
| Query-string sorting across relations | Explicit orderBy allow-list in a query builder / spatie/laravel-query-builder |
| Pagination + count over to-many joins | ->distinct()->count(), then page on the entity, not the join |
| Route versioning / negotiation | /api/v1 prefix plus middleware inspecting Accept |
Day-to-day workflow: keep one triad per resource (Request, Resource, Controller), register behind auth:sanctum, and write feature tests with $this->getJson(). This is the discipline the bundle is trying to enforce — you can get it without the dependency.
The v4.2.1 fix is worth stealing as a pattern. If you sort or paginate a Laravel query that joins a hasMany (or any to-many), you hit the exact same bug the bundle just fixed: count() over-counts rows, and limit truncates entities nondeterministically because duplicates land inside the window. The bundle's fix is a good template:
DISTINCT on the root entity's identifier, not COUNT(*)MIN for ascending, MAX for descending), grouped by the root id, so the fan-out collapses before the LIMIT is appliedgroupBy/having/aggregate on top of the existing QueryBuilder rather than rewriting it into subqueries (which is what Doctrine's Paginator does, and why the bundle rejected it)Your equivalent in Eloquent: ->select('authors.*')->selectRaw('MIN(books.title) as sort_key')->groupBy('authors.id')->orderBy('sort_key')->paginate($perPage) — plus a DISTINCT count. Prefer this over ->with() + load-and-slice for large datasets.
Hybrid integration tip: go contract-first. Publish an OpenAPI spec, implement it in Symfony with the bundle, consume it from Laravel with Http::retry()->timeout(). Treat it as a service boundary, not a library.
If you are actually in Symfony: attribute routing on the action, one DTO per action, let the bundle's normalizer handle output, and add a kernel exception listener so domain exceptions map to the same error shape. Consistency of the error envelope is the only thing that reliably pays off.
How can I help you explore Laravel packages today?