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

Jsonrpc Params Symfony Validator Sdk Laravel Package

yoanm/jsonrpc-params-symfony-validator-sdk

Symfony Validator integration for JSON-RPC params: validate incoming request parameters against Symfony validation constraints and mapping rules, with clean violation handling for yoanm/jsonrpc-server-sdk.

View on GitHub
Deep Wiki
Context7

Getting Started

This is glue, not a framework: it wires the yoanm/jsonrpc-server-sdk params-validation contract to symfony/validator so you can describe your JSON-RPC method params as a constrained DTO instead of hand-rolling if (!isset($params['email'])) checks.

composer require yoanm/jsonrpc-params-symfony-validator-sdk
composer show yoanm/jsonrpc-params-symfony-validator-sdk   # see which server-sdk + validator versions it pins

Where to look first, in this order:

  1. src/ — it is a handful of classes (a ParamsValidator, an exception, probably a ValidatedParams value object). Read it in five minutes; you will rely on it more than the README.
  2. composer.json — confirm the yoanm/jsonrpc-server-sdk constraint and the symfony/validator major it expects. This is the main upgrade-compatibility surface.
  3. tests/ — the closest thing to documentation for the exact constructor signature.

There is no Laravel package discovery here. In a Laravel app you bind the Symfony validator yourself:

// AppServiceProvider::register()
$this->app->singleton(ValidatorInterface::class, fn () => Validation::createValidatorBuilder()
    ->enableAttributeMapping()
    ->setConstraintValidatorFactory(new ContainerConstraintValidatorFactory($this->app))
    ->getValidator());

First use case — a user.create method:

final class CreateUserParams
{
    #[Assert\NotBlank]
    #[Assert\Email]
    public string $email;

    #[Assert\NotBlank]
    #[Assert\Length(min: 2, max: 64)]
    public string $name;
}

Validate the decoded params object against CreateUserParams before your handler runs; a failure becomes JSON-RPC -32602 Invalid params without a single line of defensive code in the handler.

Implementation Patterns

One params class per method, registered declaratively. Keep a map in config — 'user.create' => [Handler::class, CreateUserParams::class] — and let a small factory build the method with its validator attached. Validation rules then live next to the DTO, reviewable in one diff, not scattered through the handler.

Reuse DTOs across methods via validation groups. user.update wants all-optional fields; user.create wants required ones. One UserParams class, #[Assert\NotBlank(groups: ['create'])], and pass the group through the per-method validator configuration rather than cloning the DTO.

Handle positional params explicitly. JSON-RPC allows [1, 2] as well as {"a":1,"b":2}. Symfony constraints assume named structure, so either declare the method named-params-only (and reject arrays as invalid params) or normalize positional input to an assoc array before validation. Pick one and document it in the method's schema — mixed clients are the #1 source of confusing This value should not be blank reports.

Nested structures need #[Assert\Valid]. For an address sub-object or a lineItems array, the cascade does not happen automatically — without Valid, your nested rules silently validate nothing.

Turn violations into a stable error contract. Iterate the ConstraintViolationListInterface once and emit:

'data' => ['violations' => array_map(fn ($v) => [
    'path'    => $v->getPropertyPath(),
    'message' => $v->getMessage(),
], iterator_to_array($violations))]

Keep that shape fixed; clients will build form-error mapping on it.

Domain rules as custom constraints. A UniqueEmail constraint with a validator that hits Eloquent keeps database-touching rules inside the same pipeline as format rules. With ContainerConstraintValidatorFactory wired to Laravel's container (as above), your constraint validators get constructor injection for free.

Decorate for observability. Wrap the SDK's params validator in your own LoggingParamsValidator (or wrap at the method level if no interface is exposed) to count rejects per method — invalid-params spikes are usually a client release, and you want that graph.

Test at two levels. The DTO constraints are testable with Validation::createValidator() and no transport at all — fast, no RPC fixtures. Then one end-to-end test per method proving the -32602 envelope.

Gotchas and Tips

Three similarly-named SDKs. params-symfony-validator-sdk (validation via constraints), params-symfony-constraint-sdk, and the JSON-Schema variant all occupy the same slot. Pick based on where your rules already live; do not install two and chain them.

Symfony validator never coerces types. A client sending {"age": "42"} fails Assert\Type('int') while passing Assert\Positive. Decide your strictness policy deliberately — lenient clients want Assert\Positive + a cast, strict ones want Type. Whichever you choose, be aware Assert\Type and Assert\Positive disagree about the same payload.

Extra keys pass silently. Symfony does not fail on unknown properties for object validation. A client typo ("emial") validates cleanly and your handler reads a missing value. Guard named-param methods with Assert\Collection(allowExtraFields: false, allowMissingFields: false) or fail the method's schema contract explicitly.

Constraint messages are client-facing. By default you get raw English (This value should not be blank.). If your API is localized, configure a translator on the builder (Symfony's Translator + the validator translation domain). Also consider whether getPropertyPath() leaks internal DTO field names that differ from your public param names — remap if so.

Never build the validator per request. In Octane/RoadRunner/queue workers the compiled metadata cache is meant to be reused; a per-call Validation::createValidator() throws that away. Singleton in the container, always.

Debugging -32602 in a non-HTTP layer. The Symfony profiler shows nothing when validation fails before the controller. Temporarily log the full ConstraintViolationList (path + code + parameters) at the catch site in your params validator; that is where the truth lives.

Container wiring trap for custom constraints. Symfony's default ConstraintValidatorFactory does new YourValidator() — no Laravel DI, so __construct(Repository $r) blows up with an unhelpful argument-count error. Use ContainerConstraintValidatorFactory from symfony/validator (Laravel's container satisfies its PSR-11 requirement) and register your validators.

Maturity risk is real. One star, zero dependents, single maintainer, released a couple of weeks ago. Pin the version in composer.json, keep the validation wiring behind your own thin interface, and if the package stalls the escape hatch is trivial: the whole thing is $validator->validate($params, null, $groups) plus an exception. Fifty lines of your own adapter costs less than being blocked on an abandoned dependency.

Extension point worth knowing: because validation happens strictly before your handler, anything needing the database (uniqueness, foreign keys) belongs in a constraint, while anything needing multiple params cross-referenced belongs in a class-level constraint on the DTO — not in the handler, or you lose the uniform error envelope.

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.
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator