PHP cookbook · Beginner
Validate JSON API input in PHP
Validate and normalize a JSON request body, returning all errors in a consistent 422 response.
Approach
Decode JSON with JSON_THROW_ON_ERROR, validate each field, collect all errors keyed by field, and return them as application/problem+json with status 422. Convert valid input into a typed DTO so downstream code doesn't touch raw arrays.
Solution
<?php
declare(strict_types=1);
final readonly class CreateProduct
{
public function __construct(public string $name, public int $priceCents, public array $tags) {}
}
function parseCreateProduct(string $json): CreateProduct
{
try {
$data = json_decode($json, true, 32, JSON_THROW_ON_ERROR);
} catch (JsonException) {
throw new ValidationFailed(['body' => 'Malformed JSON']);
}
$errors = [];
$name = trim((string) ($data['name'] ?? ''));
if ($name === '' || mb_strlen($name) > 200) $errors['name'] = 'Required, max 200 characters';
$price = filter_var($data['price_cents'] ?? null, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]]);
if ($price === false) $errors['price_cents'] = 'Must be a non-negative integer';
$tags = $data['tags'] ?? [];
if (!is_array($tags) || count($tags) > 10 || array_filter($tags, fn ($t) => !is_string($t))) $errors['tags'] = 'Up to 10 strings';
if ($errors) throw new ValidationFailed($errors);
return new CreateProduct($name, $price, array_values(array_unique($tags)));
}
// Error handler:
// http_response_code(422); header('Content-Type: application/problem+json');
// echo json_encode(['title' => 'Validation failed', 'status' => 422, 'errors' => $e->errors]);
Pitfalls
- Stopping at the first error (users fix one field at a time).
- Loose comparisons (
'1abc' == 1in PHP 7). - Using
(int)casts that silently turn garbage into 0.
Variations
- symfony/validator with attribute constraints on DTOs.
- Laravel Form Requests or
Validator::make()with rules.
Further reading: PHP manual: json_decode
Reference: https://www.php.net/manual/en/function.json-decode.php
More PHP recipes
- Add CSRF protection to PHP forms
- Add health check endpoints to a PHP app
- Add structured logging with request IDs in PHP
- Build a secure password reset flow in PHP
- Cache expensive queries with Redis in PHP
- Call external APIs with timeouts and retries in PHP
- Handle file uploads securely in PHP
- Implement rate limiting in a PHP API