Skip to content

BooleanFilter Rejects Supported true/false Query Values Due to Laravel Validation Mismatch #8481

Description

@PicassoHouessou

API Platform version(s) affected: 4.3.17 (api-platform/laravel)

Description

ApiPlatform\Laravel\Eloquent\Filter\BooleanFilter::apply() accepts four string values for a boolean query parameter: 'true', 'false', '1', '0' (see BOOLEAN_VALUES map in the filter itself).

However, ApiPlatform\Laravel\Metadata\ParameterValidationResourceMetadataCollectionFactory::addSchemaValidation() auto-generates a Laravel validation constraint from the parameter's JSON schema. Because BooleanFilter::getSchema() returns ['type' => 'boolean'], the factory adds Laravel's built-in boolean validation rule to the parameter.

Laravel's boolean rule (Illuminate\Validation\Concerns\ValidatesAttributes::validateBoolean()) only accepts true, false, 1, 0, '1', '0' — it does not accept the strings 'true' / 'false'.

Since query string parameters always arrive as strings, this means:

  • ?enabled=1 / ?enabled=0 → passes Laravel's boolean rule → filter applies correctly
  • ?enabled=true / ?enabled=falsefails Laravel's boolean rule with a 422 Validation Error, before the request ever reaches BooleanFilter::apply()

So two out of the four values the filter's own code explicitly supports are rejected upstream by validation added by the framework itself, with an error message ("The enabled field must be true or false.") that is misleading given the actual literal values true/false are the ones being rejected.

How to reproduce

Any Eloquent resource with a BooleanFilter-backed QueryParameter:

#[GetCollection(
    parameters: [
        'enabled' => new QueryParameter(key: 'enabled', filter: BooleanFilter::class),
    ]
)]
class PaymentMethod extends Model
{
    protected function casts(): array
    {
        return ['enabled' => 'boolean'];
    }
}
GET /api/payment_methods?enabled=true
→ 422 {"detail":"The enabled field must be true or false.","violations":[{"propertyPath":"enabled","message":"The enabled field must be true or false."}]}

GET /api/payment_methods?enabled=1
→ 200 OK (filter applies as expected)

Possible Solution

Either:

  1. Change ParameterValidationResourceMetadataCollectionFactory::addSchemaValidation() to use a custom in:true,false,1,0 rule (or a dedicated rule object) instead of Laravel's native boolean rule when the schema type is boolean, so the generated validation constraint matches exactly what BooleanFilter::apply() actually accepts.
  2. Or narrow BooleanFilter::BOOLEAN_VALUES to only the values Laravel's boolean rule accepts ('1', '0'), and document that 'true'/'false' are not supported — though this is a more visible behavior change for existing users relying on 'true'/'false'.

Option 1 seems preferable since it fixes the validator to match the filter's documented/implemented contract rather than silently narrowing filter behavior.

Additional Context

  • BooleanFilter: vendor/api-platform/laravel/Eloquent/Filter/BooleanFilter.php
  • Validation factory: vendor/api-platform/laravel/Metadata/ParameterValidationResourceMetadataCollectionFactory.php
  • Workaround applied in our app: send 1/0 instead of true/false from the frontend query builder (no backend change needed, since 1/0 already pass Laravel's boolean rule and are in BooleanFilter::BOOLEAN_VALUES).
  • This was initially misdiagnosed as an authorization/permissions bug (403 from AccessCheckerProvider) during application-level testing before being traced to this validation-layer 422/type mismatch — worth noting for anyone else debugging a similarly confusing failure mode, since the actual HTTP status code and body received during triage can vary depending on which stack layer surfaces the error first.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions