Expression Engine
About 414 wordsAbout 1 min
enginesexpressionrelationsoperators
The Expression engine accepts an explicit field/operator/value structure and applies approved conditions automatically. It is a strong fit for APIs whose clients send nested operator objects and relational field paths.
Choose Expression when
- Operators should be visible in the request structure.
- The frontend sends filter objects rather than compact strings.
- Direct and deeply nested relations are part of the API contract.
- You do not need client-defined
ANDandORgroups.
Request shape
GET /api/posts?filter[status][eq]=published&filter[views][gte]=100The request clearly identifies each field, operator, and value. Equality may use the configured default operator:
GET /api/posts?filter[status]=publishedMinimal example
use App\Models\Post;
use Kettasoft\Filterable\Filterable;
$posts = Filterable::for(Post::class, $request)
->using('expression')
->setAllowedFields(['status', 'views', 'created_at'])
->allowedOperators(['eq', 'gte', 'between'])
->latest()
->paginate();Filterable normalizes each condition, creates a Payload, validates the policy, and applies the matching operator strategy.
Relational fields
Expression accepts dot-notated relations inside the filter structure:
GET /api/posts?filter[author.profile.name][like]=ahmedAuthorize both the relation path and its public fields:
$posts = Filterable::for(Post::class, $request)
->using('expression')
->setAllowedFields(['status'])
->allowRelations([
'author.profile' => ['name'],
'tags' => ['name'],
])
->paginate();Use ['tags'] or ['tags' => ['*']] only when every field on that relation is intentionally public.
Accepted condition forms
Expression can normalize common structured inputs:
['status' => 'published']
['views' => ['gte' => 100]]
['price' => ['operator' => 'between', 'value' => [10, 50]]]Choose one representation for an endpoint and document it consistently for client developers.
Strict and permissive modes
Use strict mode when an invalid field or operator should fail the request:
->using('expression')
->strict()
->setAllowedFields(['status', 'views'])
->allowedOperators(['eq', 'gte'])Use permissive mode when unsupported conditions may be skipped. Inspect skipped() when you need diagnostics or client feedback.
Column validation
The Expression engine can validate direct columns before generating conditions. Configure this behavior under engines.expression.validate_columns in config/filterable.php.
Relation fields are governed by allowRelations() rather than direct table-column validation.
Common mistakes
- Treating a relation path as allowed because its root relation is allowed.
- Exposing all operators when the endpoint only needs equality and range filters.
- Mixing several condition representations within the same public API.
- Choosing Expression when the client needs grouped boolean logic; use the Tree engine instead.
Next steps
- Review relational request examples.
- Configure operator strategies.
- Learn about strictness and exceptions.
