DEV Community

Cover image for Laravel integer:strict Validation Rule Explained
devTalk
devTalk

Posted on Originally published at dev-talk.com

Laravel integer:strict Validation Rule Explained

Here is a small surprise in Laravel validation. The integer rule passes the string "10". For a form that is fine, because browsers send everything as text. For a JSON API it is a quiet contract break: your docs say age is an integer, a client sends "age": "10", and you accept it. Laravel has a one-word fix, integer:strict. I ran both rules against a table of values on Laravel 13.35.0 so you can see exactly what changes, including a few results I did not expect.

The tip in one line

$request->validate([
    'age' => ['required', 'integer:strict'],
]);
Enter fullscreen mode Exit fullscreen mode

The Laravel documentation describes the strict parameter as considering the field valid only if its type is integer, so strings with integer values are invalid. It also notes that plain integer does not check the PHP variable type, only that the input is accepted by PHP's FILTER_VALIDATE_INT. The framework source shows the difference clearly: strict mode is is_int($value), and normal mode is filter_var($value, FILTER_VALIDATE_INT) !== false.

What actually passes

I ran each value through the real validator. Here are the results, with 10.0 meaning a float and "10" a string:

Value integer integer:strict
10 (int) pass pass
0 (int) pass pass
"10" pass fail
10.0 (float) pass fail
true pass fail
" 10" (leading space) pass fail
"+10" pass fail
"10.0" fail fail
"010" fail fail
1.5 fail fail
"abc", false, null fail fail

The tip is right: with integer:strict, "10", 10.0 and true all fail, and only a real int passes. The surprise is on the left side. Plain integer accepts true, and also strings with a leading space or plus sign. So a client sending {"quantity": true} gets through the normal rule. That is exactly the kind of input that ends up as 1 in your database.

Where strict mode works, and where it breaks

This is the part that can bite you. Strict mode checks the PHP type of the value, so it depends on how the data arrived:

  • JSON request body: types survive. Decoding {"age":10,"age_s":"10","age_f":10.0,"age_b":true} gave an int, a string, a float and a bool, so strict validation can tell them apart. This is the case it is built for.
  • HTML forms and query strings (?page=2): every value is text. integer:strict would reject all of them, including a perfectly normal 2. Use plain integer there.

If one endpoint serves both JSON clients and form posts, do not apply strict mode to it blindly. Test it with the real kind of requests your clients send.

The same idea for numeric and boolean

The documentation shows a strict parameter for two related rules, and I tested both:

  • numeric:strict rejects numeric strings. In my run "10" failed, while 10, 10.0 and 1.5 passed. Use it for prices and amounts where you want a JSON number, not text.
  • boolean:strict accepts only real true and false. Plain boolean also accepted 1, 0, "1" and "0", and all four failed in strict mode. Note that "true" as a string fails both versions.
$request->validate([
    'quantity'  => ['required', 'integer:strict', 'min:1'],
    'price'     => ['required', 'numeric:strict'],
    'gift_wrap' => ['required', 'boolean:strict'],
]);
Enter fullscreen mode Exit fullscreen mode

Missing and null values

Strict mode does not change how required and nullable work. With required|integer:strict, a missing field failed. A null value failed unless the rule list included nullable, and with nullable|integer:strict it passed. Add nullable only on fields that are really optional.

Should you use it?

For a public JSON API with documented types, yes. It gives clients a clear error the first time they send the wrong type, instead of letting sloppy data in and fixing it later. The honest trade-off: stricter rules mean some existing clients that send "10" will start getting 422 errors. If that is a risk, roll it out on new endpoints first, or version the API.

References


Originally published on DEV Talk.

Top comments (0)