Installation Add the package via Composer:
composer require laravel-json-api/validation
Publish the config (optional, but useful for customization):
php artisan vendor:publish --provider="LaravelJsonApi\Validation\ValidationServiceProvider"
First Use Case Validate a JSON:API request payload against a resource schema:
use LaravelJsonApi\Validation\ValidatesJsonApiResource;
class StoreUserRequest extends FormRequest
{
use ValidatesJsonApiResource;
public function rules()
{
return [
'data' => ['required', 'array'],
'data.type' => ['required', 'string', 'in:users'],
'data.attributes' => ['required', 'array'],
'data.attributes.name' => ['required', 'string'],
'data.attributes.email' => ['required', 'email'],
];
}
}
Key Config
Check config/json-api-validation.php for default settings (e.g., allowed attributes, nested validation depth).
Use ValidatesJsonApiResource to enforce JSON:API structure:
use LaravelJsonApi\Validation\ValidatesJsonApiResource;
class UpdatePostRequest extends FormRequest
{
use ValidatesJsonApiResource;
protected $resource = Post::class; // Auto-generates rules for Post model
}
Validate nested attributes dynamically:
public function rules()
{
return [
'data.attributes' => ['required', 'array'],
'data.attributes.title' => ['required', 'string', 'max:255'],
'data.attributes.body' => ['required', 'string'],
'data.relationships.author' => ['required', 'array'],
'data.relationships.author.data' => ['required', 'array'],
];
}
Extend validation with custom rules:
use LaravelJsonApi\Validation\Rules\JsonApiRule;
public function rules()
{
return [
'data.attributes.published_at' => [
'nullable',
new JsonApiRule\DateTimeFormat('Y-m-d\TH:i:sP'),
],
];
}
Use with laravel-json-api/server for seamless validation:
// In a controller using laravel-json-api/server
public function update(Request $request, Post $post)
{
$this->validate($request, new UpdatePostRequest);
// Proceed with update logic
}
Test validation in PHPUnit:
public function test_validation_fails_on_missing_required_field()
{
$response = $this->postJson('/posts', [
'data' => ['type' => 'posts', 'attributes' => []] // Missing 'title'
]);
$response->assertUnprocessable()
->assertJsonValidationErrors(['data.attributes.title']);
}
Missing data Key
Always ensure the request includes a data key. The validator assumes JSON:API structure by default.
Nested Validation Depth
Deeply nested relationships may hit Laravel’s default validation recursion limit. Adjust config/json-api-validation.php:
'max_nesting_level' => 10,
Case Sensitivity
JSON:API type fields are case-sensitive. Ensure consistency (e.g., users vs Users).
Overriding Auto-Generated Rules
If using $resource, manually defined rules will override auto-generated ones. Explicitly merge them if needed:
public function rules()
{
return array_merge(
$this->getJsonApiResourceRules(),
['data.attributes.custom_field' => 'required']
);
}
Enable Debug Mode
Set 'debug' => true in config to log validation errors in detail.
Check for Silent Failures
Ensure data is always validated, even if other fields are optional:
'data' => ['required', 'array'],
Use toArray() for Inspection
Convert the request to an array to debug structure:
dd($this->all());
Custom Rules
Extend JsonApiRule for domain-specific logic:
namespace App\Rules;
use LaravelJsonApi\Validation\Rules\JsonApiRule;
class UniqueSlug extends JsonApiRule
{
public function passes($attribute, $value)
{
return !Post::where('slug', $value)->exists();
}
}
Modify Default Rules
Override JsonApiResourceValidator in a service provider:
$this->app->bind(JsonApiResourceValidator::class, function ($app) {
return new CustomJsonApiResourceValidator($app['validator']);
});
Conditional Validation Use Laravel’s built-in conditional rules:
'data.attributes.password' => [
'required_if:data.attributes.reset_password,1',
'string',
'min:8',
],
How can I help you explore Laravel packages today?