Selecting keys does not validate values
request->only selects names present in input. It does not know that quantity must be a positive integer or an email must have valid syntax. A FormRequest or validator applies rules; validated returns the result and safe allows selecting a subset of that validated set.
In the example, the service receives the prepared payload and does not reread all. Do not turn this discipline into an authorization claim: validating data does not decide who may modify a resource.
Absent, empty and null
In the scenario’s PATCH, absence of email means leaving that data unchanged. If email is supplied, the team requires a non-empty valid value: sometimes|required|email expresses that distinction. nullable expresses another decision, acceptance of null.
With default normalization middleware, an empty string may become null before rules. For optional publish_at, nullable|date permits that state while still rejecting non-null values that are not valid dates.
Transformation timing
prepareForValidation can prepare input before rules. Use it for normalization accepted by the contract, such as making a code representation canonical, not for silently accepting any defective value. passedValidation occurs after rules, so transforming input there does not establish that the transformed value was validated.
Identify which representation the rules observed and which reaches the service, especially if other code changes the request after validation.
Arrays need a key boundary
The array rule alone validates the outer type and can allow inner keys without their own rules to remain in validated output. In the example, array:display_name,email rejects additional properties; field rules additionally define presence, type and content.
This combination prevents profile.is_admin from being treated as an ordinary field merely because the name passed. Persistence should still enforce its own boundaries; the key list does not replace access policies or authorization.
Exclusion also selects the output
exclude_if removes a field from the result returned by validate or validated when the condition matches. If tax_id is excluded for type=personal, copying it afterwards from all into the service undoes that boundary. Do not assume a validation rule rewrote the entire raw request.
In update uniqueness rules, the ignored identity should come from the server’s known authorized model. A hidden ignore_id field remains client-controlled and is not a trustworthy source.
Local failures and global stopping
bail stops subsequent rules for the failed field. It neither turns failure into a warning nor requires stopping every other field. Validator stopOnFirstFailure has global scope; version 13 also documents an equivalent FormRequest attribute option.
In the exercises, explicit absence of that global control allows predicting that other fields may still be validated. Choose error policy intentionally: fewer rules executed does not mean accepted data.
Authorize, validate and respond
When FormRequest authorize returns false, normal handling returns 403 and does not execute the controller action. A ValidationException for a request expecting JSON instead returns 422 with messages and errors; nested keys appear in dot notation.
Do not replace access refusal with a format correction or interpret every 4xx response as the same problem. The client should preserve appropriate editing data and present errors corresponding to the contract actually violated.
<?php
// Rules excerpt from a profile FormRequest; authorization is separate.
public function rules(): array
{
return [
'profile' => ['required', 'array:display_name,email'],
'profile.display_name' => ['required', 'string', 'max:80'],
'profile.email' => ['sometimes', 'required', 'email'],
'publish_at' => ['nullable', 'date'],
];
}
// Consumer excerpt after successful FormRequest validation.
$payload = $request->safe()->only(['profile', 'publish_at']);The action accepts profile only with display_name and email. A profile.is_admin key causes failure because of the allowed-key list even when the name is valid. Email may be absent but not empty when supplied. publish_at may be null or a valid date.
The excerpt implements neither authorize, persistence nor a complete profile policy; those decisions remain separate.
Common pitfalls
Treating only as a validator; confusing nullable with sometimes; assuming array validates every key; passing client input to unique ignore; interpreting bail as global stopping; treating valid format as authorization.
Related topics: Routes, binding and middleware · Eloquent, relationships and query cost · Authentication, authorization and sessions
The contract includes presence, values, keys and operation identity. Apply rules to the correct representation, restrict the result delivered to the service and keep authorization separate. Explain observed failure from the stage where it occurred.
Reference: Validated input selection · Laravel 13.x; PHP 8.3+