Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Schema Laravel Package

krak/schema

krak/schema is a lightweight Laravel/PHP package for defining, validating, and managing application schemas. It provides a simple, framework-friendly API to keep schema logic organized, reusable, and easy to integrate into your project.

View on GitHub
Deep Wiki
Context7

Getting Started

krak/schema is a small, low-level package for declaring data schemas and running values through them. It is not a Laravel-first package, so expect to wire it in yourself. Version 0.2.0 is the current release and contains a BC change from 0.1.0: the package now distinguishes struct nodes (fixed, named keys) from dict nodes (dynamic/map-like keys), and prior dict usage was replaced with struct. Read the changelog before upgrading.

  1. Install: composer require krak/schema:^0.2. If you already used 0.1.0, do not float blindly across the major/minor boundary without reading the release notes and testing. Check resolution with composer why-not krak/schema if needed.
  2. Read the source first. With a single star and no dependents, the repository is the documentation. Browse src/ on GitHub before writing code. Look for the primary Schema class, the node classes, and specifically how struct and dict are represented after 0.2.0.
  3. Skim composer.json for the autoload namespace (likely Krak\Schema\) and the PHP version floor. This tells you what language features the internals rely on. The package is old enough that PHP 8.1/8.2 deprecations are worth checking.
  4. First use case: declare a schema for an incoming associative array payload — a webhook body or API resource — using a struct for the fixed-key record, then run the raw array through it to get a normalized, typed structure instead of hand-writing isset()/is_string() ladders.
// Illustrative shape — verify exact API names in src/
use Krak\Schema\Schema;

$schema = Schema::make([
    'id'    => 'int',
    'email' => 'string',
    'tags'  => ['string'], // collection/list semantics, not a fixed-key struct
]);

$clean = $schema->process($request->all());

Start with one payload type, get it working end-to-end in a test, then expand.

Implementation Patterns

One schema per payload type. Create a small class per domain concept (CreateOrderSchema, WebhookPayloadSchema) rather than inline arrays scattered across controllers. This makes them testable in isolation and gives you a single place to change when an upstream contract moves:

class CreateOrderSchema extends Schema
{
    protected function definition(): array
    {
        return [
            'customer_id' => 'int',
            'lines'       => [[/* line schema */]],
        ];
    }
}

Process at the boundary, not in the model. Invoke schemas in FormRequests, controllers, or queued-job handlers — wherever external data enters. Keep Eloquent models and domain services working with already-normalized arrays/DTOs. This mirrors how you'd use Laravel's Validator, so it slots into existing habits.

Use structs for records, dicts for maps. After 0.2.0, be deliberate about the distinction:

  • Struct: fixed, known keys — customer_id, email, lines. This is what most request/resource payloads should be.
  • Dict: dynamic/map-like data — arbitrary keys, translation maps, metadata bags.

If you are migrating from 0.1.0, audit every place you previously used dict for what was really a fixed-key record. That is the BC break: those should now be struct definitions. Keep true maps as dict.

Compose schemas for nesting. Build a library of leaf schemas (AddressSchema, MoneySchema) and compose upward. This is where a schema package earns its keep over inline validation — reuse and nesting — so lean into it. Check whether 0.2.0 struct nodes compose more cleanly than the old dict-based nesting; they usually do.

Pipeline processing. If the package exposes ordered processors, treat them as a normalization pipeline: coerce types → apply defaults → validate constraints. Keep each step single-purpose so failures are easy to localize.

Laravel integration. There is no service provider you should expect to be auto-discovered. Register schemas as singletons in AppServiceProvider if they're expensive to build, or just new them — they're cheap value objects. Consider a Schema::processOrFail() wrapper that throws a ValidationException so failures surface through Laravel's normal error handling:

try {
    $data = $schema->process($input);
} catch (\Throwable $e) {
    throw ValidationException::withMessages(['payload' => $e->getMessage()]);
}

Test schemas directly. For each schema, assert: valid input passes and is normalized as expected; missing required fields fail; wrong types fail or coerce (know which); extra/unknown keys are handled predictably; struct and dict schemas behave differently in the expected ways. These tests are cheap and become your real documentation. Add explicit regression tests when upgrading from 0.1.0 to 0.2.0.

Gotchas and Tips

  • 0.2.0 is a BC release. The struct/dict split is the headline. If you are on 0.1.0, pin before upgrading and run your schema tests. Search your code for every dict usage and classify it: fixed-key record → struct; true dynamic map → keep dict. Tests that relied on old dict semantics for records will fail or, worse, silently accept the wrong shape.
  • Maintenance risk is still the headline. One star, zero dependents, last release April 2020 before this update. Treat it as a vendored dependency: if it breaks on a PHP upgrade, you will be fixing it yourself. Consider copying the handful of classes into app/Support/ and dropping the Composer dependency — for a package this small that is often the safer long-term move.
  • No docs, no safety net. Do not assume method names from this assessment; confirm against src/. Budget an hour to read every class — it's small enough to read fully, which is the main advantage of an obscure package. After 0.2.0, specifically read the struct and dict node classes.
  • PHP 8 compatibility. Code from 2020 may predate PHP 8.1/8.2 deprecations (dynamic properties, null to non-nullable internals). Run your test suite with E_ALL and a strict error handler before trusting it in production.
  • Type coercion is where bugs hide. Determine deliberately: does "5" become 5? Does "yes" become true? Does null satisfy a required field? Write explicit tests for each, because these semantics are the package's whole value proposition and the least likely thing to be documented.
  • Unknown-key policy. Decide and test whether extra keys are silently dropped, preserved, or rejected. With the new struct/dict distinction, this may differ between the two node types. Dropping them silently is the most common surprise when wiring into an existing API.
  • No Laravel ergonomics. No config file, no facades, no auto-discovery, no localization of messages. Wrap error output yourself if you need user-facing messages.
  • Extension points are your escape hatch. Subclass the base schema or register a custom processor (whichever the package exposes) rather than editing vendor code — unless you've already decided to vendor the source, in which case edit freely and document it. Check whether 0.2.0 changed the extension points around structs and dicts.
  • Debugging: since errors will be package exceptions rather than Laravel validation errors, log the raw input alongside the exception during rollout to distinguish "bad client data" from "schema mismatch." During the 0.1.0 → 0.2.0 migration, also log whether the failing schema was expected to be a struct or a dict; that is the most likely source of upgrade breakage.
  • Symfony config test change is internal. The release notes mention a Symfony config feature test no longer relying on the dumper reference. That is not a Laravel integration and should not affect your usage, but it confirms the package still has non-Laravel test fixtures. Do not infer a Laravel service provider from it.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package