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 Filter Bundle Laravel Package

monterhealth/api-filter-bundle

MonterHealth ApiFilterBundle adds request-driven filtering to Doctrine queries in Symfony APIs. Declare allowed filters on entities, map query parameters automatically, and keep controllers clean while supporting flexible, validated search endpoints.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the honest headline for a Laravel developer: this is a Symfony bundle, not a Laravel package. It targets Symfony's HTTP kernel, DI container, and (almost certainly) Doctrine ORM. There is no service provider, no facade, no config/api-filter.php. You cannot composer require it into a Laravel app and expect it to work. If you are evaluating it for a Laravel codebase, you are really evaluating the pattern it implements — declarative, whitelist-driven filtering and ordering of REST list endpoints — and deciding whether to port that pattern or adopt a native equivalent.

If you are in a Symfony project (or maintaining one alongside Laravel work), the minimal path is:

  1. composer require monterhealth/api-filter-bundle
  2. Register the bundle in config/bundles.php (Symfony Flex will usually do this).
  3. Read the README's annotation/attribute examples — that is where the contract lives: which entity properties you mark as filterable and sortable, and what query-string shape the bundle expects (typically something like ?filter[field]=value&order[field]=asc).
  4. Look first at the request listener / param resolver and the annotation or PHP-attribute classes. Those two files tell you the entire supported surface area faster than the docs will.
  5. First use case: a paginated GET /articles endpoint where the client can filter by a handful of whitelisted columns and sort by one or two. Wire it into a controller that hands a QueryBuilder to the bundle and returns the paginated result.

For Laravel, the pragmatic equivalents to benchmark against are spatie/laravel-query-builder (closest in spirit), plain Eloquent local scopes, or a small custom middleware + query-object layer. Only port this bundle's classes if you specifically want its annotation-driven, entity-coupled style; otherwise you are reimplementing something Laravel already does more idiomatically.

Implementation Patterns

The bundle's model is declarative whitelisting co-located with the model. You annotate (or attribute) entity properties as filterable/sortable, and the bundle translates incoming query parameters into query-builder constraints, ignoring anything not whitelisted. Day-to-day, that produces a few recurring patterns:

  • Controller-driven application. A controller receives the Request, obtains a QueryBuilder from a repository, applies the bundle's filter/order step, and paginates. Keep this in one place (a base controller or a thin service) so every list endpoint behaves identically.
  • Separate filter and order whitelists. Filterable and sortable are distinct concerns — a column you expose for equality filtering is not necessarily one you want clients sorting large tables by. Treat them as two configs.
  • Combine with pagination and total counts deliberately. Filtering changes the count query; make sure whatever paginator you use is fed the filtered builder, not the raw one.
  • Repository-level reuse. If you apply filters inside repository methods rather than controllers, you get consistent behaviour across HTTP and console/queue callers. This is the cleaner integration for larger apps.
  • Custom filter types as extension points. Equality filters are the baseline; range, IN, date, and relation filters usually need explicit handling. The bundle's extension seam is where you add these rather than bolting logic into controllers.
  • Test the whitelist, not just the happy path. Write feature tests that assert unknown fields are ignored (or rejected) and that ordering by a non-whitelisted column is refused. This is the contract clients depend on.

Mapping to Laravel if you port the idea: validate and normalize query params in a form request or a dedicated query object, resolve them against a whitelist array (ideally next to the model or in a Filterable concern), then apply Eloquent scopes. Keep the same separation — filter whitelist vs. sort whitelist — and return a typed result rather than mutating the builder in place in the controller. A base ListRequest + applyFilters(Builder $query) trait gets you 90% of this bundle's value in a few dozen lines.

Gotchas and Tips

  • Framework lock-in is the dominant gotcha. Symfony kernel events + Doctrine QueryBuilder mean the classes are not drop-in portable to Laravel. If porting, take the design (declarative whitelists, request-to-query translation) and leave the implementations behind. MIT license makes this fine legally; the cost is engineering time.
  • Your whitelist is a public API contract. Once clients filter or sort by a field, removing it is a breaking change. Version it, document it, and be conservative about what you expose — especially sortable columns on large tables.
  • Performance is on you. Filtering and sorting by arbitrary whitelisted columns will happily do full scans if the columns aren't indexed. Audit your indexes against the sort whitelist specifically; ORDER BY on an unindexed column is the classic slow endpoint.
  • Injection safety depends on the whitelist holding. Parameter binding protects values, but field and direction names often get interpolated into DQL/SQL. Never let a field name through without matching it against the whitelist first, and validate sort direction as an enum (asc/desc), not a free string.
  • Relations need explicit support. Relation filtering and sorting usually require dedicated handling and invite N+1 queries. If you support them, eager-load deliberately and test query counts.
  • Adoption and maintenance risk. Nine stars and zero dependents is a real signal: expect thin docs, few Stack Overflow answers, and a single-maintainer bus factor. Read the source before depending on edge-case behaviour, and vendor/fork if the project is load-bearing.
  • Extension points beat patches. When you need custom behaviour, reach for the documented extension seams (custom filter/order types, or overriding the param resolver) rather than editing vendor code. If the seam doesn't exist for your case, that's a signal to wrap the bundle in your own service layer.
  • Debugging: log the resolved filter/order set (not the raw query string) and dump the final query builder before execution. On Symfony, the profiler's query panel shows exactly what the bundle produced — use it to confirm whitelisting actually rejected what you expected it to reject.
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.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings