Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Api Query Builder Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package sits in a clean seam that already exists in every Laravel API: model allowlist declarations plus a chainable call in the controller, composing on top of Illuminate\Database\Eloquent\Builder rather than replacing it. That is the strongest architectural property here — it does not introduce a new query language, a schema layer, or a runtime the team has to learn. Tenancy scoping, soft deletes, policies, and pagination stay ours; the package only contributes client-driven constraints. For a TPM, the relevant framing is that this is a thin convention over a pattern we already write by hand, not a platform commitment.

Integration feasibility. Feasible in an afternoon for a single endpoint: composer require, publish config, declare three arrays on a model, chain one method. The blocker is not effort, it is the absence of a spec. There is effectively no documentation, one maintainer, 26 stars, and zero dependents — the published config and the source are the specification. Two facts must be established from source before any planning is credible: (a) whether a model with no declared allowlist fails open or closed, and (b) whether an allowlisted include can traverse into relations we never intended to expose. Those are not implementation details; they determine whether the package is safe to point at production data at all.

Technical risk. Three risks, ranked:

  1. Compatibility / staleness (highest). July 2023 predates Laravel 11. If illuminate/* constraints are stale, we are forking on day one — a decision that must be made consciously, with budget, rather than discovered mid-sprint.
  2. Security surface (high, but mitigable). This is request-parameter parsing sitting directly in front of the ORM. Injection-adjacent code with no accountable upstream maintainer. Mitigation is ours: verify deny-by-default by hand, test ?filter[password]=1 is rejected or ignored, and never let the grammar become permissive-by-omission.
  3. Continuity / bus factor (high, but bounded). One maintainer, no ecosystem, no Stack Overflow footprint. Debugging cost is entirely ours. Bounded by pinning the exact version, naming an owner, and keeping the call site behind a feature flag.

There is no capability upside that justifies migrating off spatie/laravel-query-builder — that would be a net-negative risk swap. The legitimate cases are a greenfield minimal implementation we intend to own, or cribbing the parse-and-allowlist pattern into our own code.

Key questions to close before commitment.

  • Do illuminate/* constraints resolve on our target Laravel and PHP 8.2+? (Throwaway branch, composer update --dry-run.)
  • Does a missing allowlist entry fail open or closed? Answer from source, not README.
  • Can an allowlisted include walk to an unintended relation? Does the package cap include depth or count?
  • How does the parser handle empty and coerced values — filter[status]=, filter[id]=0, filter[active]=false, invalid dates? A truthy filter returning all rows is a client-visible correctness bug.
  • Who owns the fork, and what is the trigger condition for taking it?

Integration Approach

Stack fit. Good, with a caveat about scope. It fits any Laravel list endpoint that needs column filters, a single sort, and eager-loaded relations — admin tables, audit logs, dashboards, internal search. It does not fit surfaces needing relationship filters, sparse fieldsets, cursor pagination, or strict default-deny semantics. Match the endpoint class to the package's actual capability before promising a roadmap date.

Migration path. There is no migration — this is additive greenfield instrumentation on endpoints that today hand-roll filtering. Do not refactor existing endpoints onto it. The concrete path:

  1. Spike (timeboxed, throwaway branch): compatibility, allowlist semantics, include traversal. Output is a written answer to the five questions above, not code.
  2. Pilot (one internal list endpoint): admin users or audit log — explicitly not the customer-facing API. Define "installed correctly" as four passing checks: ?sort=-created_at orders newest first, ?filter[status]=active filters, ?filter[password]=1 is rejected/ignored, ?include=orders eager-loads with no N+1 confirmed via DB::listen or Telescope. If the third fails, stop.
  3. Pattern adoption: only after the pilot holds, extend to a second surface — at which point the allowlist arrays move to a base model or Queryable trait so they are audited in one place rather than drifting per call site.

Compatibility. Verify, don't assume. Pin exactly ("1.2.*", never ^1.0) and record the pin in an ADR with a named owner. If the constraints are stale on day one, the decision becomes "vendor and own" — which is a legitimate choice, but it must be scoped and staffed as such, not framed as a dependency addition.

Sequencing. Compatibility spike → allowlist/include security verification → pilot endpoint behind a feature flag → documented grammar (docs/api/querying.md, per-endpoint supported filters, sorts, includes) → second endpoint → decide on fork vs. wrapper scopes. The documentation step is not optional polish: with no upstream docs, the grammar we publish is the API contract, and client teams integrate against our file, not the package.

Two ordering rules to bake into review checklists: authorization scoping (whereBelongsTo($tenant)) must precede apiQuery($request) — order is a security property, not style — and pagination must have a deterministic tiebreaker (orderByDesc('created_at')->orderByDesc('id')), because the package will not add one and unstable page boundaries surface only under load.

Rollback lever. Each endpoint's adoption sits behind a config flag. The response to "sort=name is suddenly ordering by email" is a flip, not a hotfix.

Operational Impact

Maintenance. The realistic operating model is vendored code we maintain, not a dependency that receives upstream fixes. Budget accordingly: a named owner, an ADR, a pinned version, and an explicit trigger for forking. The codebase is small and readable, which caps the cost — but "small and readable" is not the same as "zero." The moment the first non-trivial filter requirement lands (filter[created_after], filter[q]=acme, filter[status][in]=a,b), the correct move is a hand-written scope appended after the builder, not bending the parser. Three such escapes in a sprint is the fork signal.

Support. Support load shifts from "write filter logic" to "explain the grammar" plus "debug why a filter returned unexpected rows." The second category is cheap to resolve if we instrument it: log SQL plus bindings for failing requests, keep a ?debug=sql toggle or Telescope tab. The first is cheap only if the grammar is documented — which is on us. Expect no community leverage; there is no Stack Overflow footprint to escalate into. Weigh this against the alternative: bespoke per-endpoint parameters produce more integration tickets and slower partner onboarding, so a documented uniform grammar is a net support-load reduction if the docs exist.

Scaling. Two dimensions:

  • Query cost. Includes are amplification, not just extra rows — ?include=orders.items.product is trivial to type and expensive to run. Cap include depth and count in the allowlist, and confirm every includable foreign key is indexed. This is ours to enforce; the package will not do it for us.
  • Surface count. The grammar's cost curve is favorable: a new filter is an allowlist entry, not new endpoint code. That compresses the delivery cost of a whole class of roadmap items — admin tables, dashboards, exports, search screens. It is a lever on iteration speed, not a differentiator, and should be tracked as cycle-time improvement rather than positioned as a product capability.

Failure modes to plan for.

Failure Symptom Mitigation
Allowlist permissive by omission Disallowed column filterable in production Verify from source pre-merge; toSql() test asserting password never appears
Include traversal Relation exposed that was never intended Manual traversal test; cap depth/count
Unstable pagination Duplicate/missing rows under load Explicit deterministic tiebreaker
Parser coercion filter[active]=false returns everything One edge-case test per resource per empty/coerced value
Ordering regression Mis-ordered orWhere widens past tenant scope Scope-before-build in review checklist
Stale dependency Breaks on next Laravel major Exact pin, named owner, ADR

Ramp-up. Low for engineers who already know Eloquent — one trait, one chained call, three arrays. The real ramp-up cost is organizational: the team must internalize deny-by-default as our responsibility, not the library's, and adopt SQL-level assertions (toSql(), not just JSON) as the test standard for every exposed resource. Run the allowlist matrix — allowed filter, disallowed filter, bad sort, disallowed include — per resource.

Recommendation. A bounded pilot on one internal list endpoint, behind a flag, with a named owner, a pinned version, a written compatibility answer, and documented grammar. Upside is measured in saved engineering weeks per surface; downside is capped at reverting a flag. Default to spatie/laravel-query-builder for anything public, customer-facing, or contractually governed — zero dependents and a stale cadence are continuity risks we should not place on an external contract.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib