Skip to content
potagerphp/grape/v0.1.1/PHP 8.2+/Zero dependencies

Type-safe schema validation
and data sanitization for PHP.

Type-safe schema validation and data sanitization for PHP 8.2+.

Documentation → Introduction
$composer require potagerphp/grape

How it works

use Potager\Grape\Grape;

$schema = Grape::schema([
    'name'  => Grape::string()->trim()->minLength(2)->required(),
    'email' => Grape::string()->trim()->lowercase()->email()->required(),
    'age'   => Grape::integer()->min(18)->optional(),
]);

// Validates and returns clean, typed data:
$data = $schema->validate($_POST);

Core capabilities

Declarative Validation

Declare strict constraints with IDE-autocompleted chainable methods. Enforce length boundaries, regex patterns, email formats, and presence requirements (required() / nullable()).

$validator = Grape::schema([
    'username' => Grape::string()->minLength(3)->maxLength(20)->required(),
    'email'    => Grape::string()->email()->required(),
    'age'      => Grape::integer()->min(18)->optional(),
]);

In-Place Data Sanitization

Clean and normalize values directly during validation. Methods like trim(), lowercase(), clamp(), and compact() transform the data so your domain receives sanitized output.

$clean = Grape::schema([
    'search' => Grape::string()->trim()->lowercase(),
    'limit'  => Grape::integer()->clamp(1, 100),
])->validate($_GET);

Strict & Loose Type Coercion

Loose mode (default) seamlessly coerces HTTP form strings like "28" → 28 and "true" → true. For strict JSON APIs, pass strict: true to enforce exact native types without casting.

Grape::number();              // Loose (casts numeric strings)
Grape::number(strict: true);  // Strict (int & float only)
Grape::boolean(strict: true); // Strict (bool only)

First-Class Composition

Nest associative schemas, homogeneous collections, and fixed-size tuples. Collections support deduplication (distinct()), invalid item skipping (skipInvalids()), and index normalization.

$order = Grape::schema([
    'tags'        => Grape::collection(Grape::string())->distinct(),
    'coordinates' => Grape::tuple([Grape::float(), Grape::float()]),
]);

Non-Throwing Result Option

Choose your error handling style. Throw structured ValidationException or use the functional check() method returning [$error, $data] to handle errors without try/catch blocks.

[$error, $data] = $schema->check($payload);

if ($error !== null) {
    return response()->json($error->getMessages(), 422);
}

Built-in types and structures