bjerke/api-query-builder
Simplify API query handling in Laravel with a fluent query builder that turns request parameters into filtered, sorted, and paginated Eloquent queries. Reduce boilerplate and keep filtering logic consistent and reusable across your endpoints.
?filter[status]=active&sort=-created_at&include=customer into safe, validated Eloquent constraints is recurring, undifferentiated work on nearly every list surface we ship — admin tables, dashboards, exports, search screens, partner feeds. This package is the candidate "buy" answer: roughly a sprint of hand-rolled request parsing saved per surface, priced against a real ownership cost.Consider it only when all of the following hold:
illuminate/* constraint is the likeliest discovery, and it means forking on day one.1.2.*, never ^1.0) and write the ADR with a name on it.include can walk into relations we never intended to expose.created_after, free-text q, status[in]=…), we append a hand-written scope rather than bending the parser. Three of those in a sprint means we stop and fork.?filter[password]=1 is rejected or ignored, ?include=orders eager-loads without N+1. If the third fails, stop.Look elsewhere when:
spatie/laravel-query-builder, which occupies the same slot with current Laravel support, an active maintainer, and a community. Do not migrate an existing Spatie shop to this — net-negative risk swap, no capability upside.For executives. We pay a recurring, low-differentiation cost on every list screen and API surface: hand-writing filter, sort, and pagination logic endpoint by endpoint. This package would let us express those as configuration plus an explicit allowlist, compressing the cost of a whole class of roadmap items and shortening partner integration time. The tradeoff is ownership — the library is small, has one maintainer, and was last released in mid-2023, so adopting it means treating it as vendored code we maintain. Recommendation: a bounded pilot on one internal list endpoint behind a feature flag, with a named owner, a pinned version, and a documented fallback. Upside is measured in saved engineering weeks; downside is capped at reverting a flag. It doesn't touch pricing, positioning, or anything customer-visible.
For engineering. This is a thin, readable implementation of the pattern we'd otherwise rewrite: declarative filters mapped to Eloquent constraints, sort and direction handling, controlled eager loading, and a chainable call in the controller. It is not a framework and has no extension ecosystem — assume a fork the first time we need a non-trivial filter. Concrete asks before we merge anything: (1) validate Laravel/PHP compatibility on a throwaway branch; (2) verify by reading source whether the allowlist is deny-by-default and whether includes can traverse unintended relations; (3) keep allowlists on the model, not at call sites, so they're auditable in one place; (4) scope authorization before the builder runs, and force a deterministic tiebreaker on sorted pagination; (5) assert on generated SQL in tests, not just JSON; (6) write the query-grammar docs ourselves, per endpoint — that file is our client contract and our checklist when a column is added. The legitimate fallback outcome is vendoring the parsing/allowlisting pattern into our own code and dropping the dependency; that's a win, not a failed pilot.
How can I help you explore Laravel packages today?