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

Api Dto Laravel Package

roadrunner/api-dto

roadrunner/api-dto provides typed Data Transfer Objects for Laravel APIs. Define DTOs to convert request arrays into structured objects, validate and cast attributes, and handle nested data, keeping controllers lean and API payloads consistent and type-safe. Designed to keep API code organized.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is the wire contract layer for RoadRunner's gRPC API: it ships the canonical .proto definitions plus pre-generated PHP classes under RoadRunner\Api\V1\*. You reach for it when you're building a RoadRunner plugin, a custom worker that speaks the RR API directly, or anything that needs to encode/decode Payload, Response, KV, Jobs, Metrics, Lock, or Informer messages without hand-rolling protobuf.

Heads-up as of v2.1.0: the package was renamed from roadrunner-php/roadrunner-api-dto to roadrunner/api-dto. The generated namespaces (RoadRunner\Api\V1\*) and the proto/ layout are unchanged — only the Composer package name moved. Install under the new name:

composer require roadrunner/api-dto

If you're already on ^2.0, treat the rename as a lockfile-level change: update the require key in your composer.json (and any replace/provide entries, CI allowlists, or dependency-review configs that reference the old name) and run composer update roadrunner/api-dto. Existing imports keep working.

You need ext-protobuf (and ext-grpc if you'll use the generated *Client stubs, since they extend Grpc\BaseStub). Verify with php -m | grep -E 'protobuf|grpc'.

First things to look at, in order:

  1. proto/ — the source of truth for every message and service. Read the .proto file for your target service before the PHP class; field numbers and oneof groupings are clearer there.
  2. src/Api/V1/ (generated) — mirror of the protos in PHP. Class names map 1:1 (Payload, Response, KV\Item, Jobs\Job, etc.).
  3. The generated *Client classes for the service you need — e.g. RoadRunner\Api\V1\KV\KVClient.

First use case — encode a payload for a service call:

use RoadRunner\Api\V1\Payload;

$payload = new Payload();
$payload->setBody('hello');
$bytes = $payload->serializeToString();

// Or over gRPC:
$client = new \RoadRunner\Api\V1\KV\KVClient(
    'unix:///tmp/rr.sock',
    ['credentials' => \Grpc\ChannelCredentials::createInsecure()]
);

Implementation Patterns

Treat DTOs as dumb wire objects, wrap them. Don't pass Payload/Response around your domain. Convert at the boundary: build a DTO, serialize, send; deserialize, then map to your own value objects. Generated classes have no validation and mutable setters, so leaking them into business logic invites inconsistent state.

Construction and nested messages. Message-typed fields must be assigned whole objects:

$item = new \RoadRunner\Api\V1\KV\Item();
$item->setKey('user:1');
$item->setValue((new Payload())->setBody($json));

Don't try to mutate $item->getValue()->setBody(...) inline unless getValue() returns a non-null instance — with proto3 it returns the default empty message, not null, which is a common source of silent bugs.

Repeated fields. getHeaders()/getItems() return a RepeatedField. Prefer the setter with an array — setHeaders(['a' => 'b']) — over mutating the RepeatedField in place; the setter is clearer and serializes predictably.

Sockets and transport. RoadRunner exposes its API on a Unix socket; the path is typically in RR_RELAY. Use the unix:// scheme for gRPC:

$socket = getenv('RR_RELAY') ?: 'unix:///tmp/rr.sock';

spiral/roadrunner-worker and spiral/goridge handle framing and socket discovery; combine them with these DTOs rather than reinventing the protocol. The DTO is the message, not the frame.

Serving a plugin. If you're implementing a RoadRunner plugin in PHP, prefer spiral/roadrunner-grpc for the server side and use the generated message classes from this package as your handlers' argument/return types. On the client side, the generated *Client stubs here should be used as-is.

Version pinning. These protos track the RoadRunner binary. Pin the package version in lockstep with your RR release (e.g. 2024.x package with 2024.x binary). When you bump RR, bump this package in the same commit — mismatched proto versions manifest as Unexpected wire type decode errors that are painful to trace.

Migration across the rename. If a third-party package (or your own split-out library) still requires roadrunner-php/roadrunner-api-dto, you can end up with two entries for what is now one project. Check with composer why roadrunner-php/roadrunner-api-dto and composer why roadrunner/api-dto; a duplicate means an upstream pin needs bumping, not a replace hack. Keep the rename in its own commit so a lockfile diff is easy to audit.

Testing. Round-trip assertions are cheap and catch field-number mistakes:

$parsed = new Payload();
$parsed->mergeFromString($payload->serializeToString());
$this->assertSame('hello', $parsed->getBody());

Gotchas and Tips

  • Old package name in docs and examples. Search results, blog posts, and many composer require snippets still say roadrunner-php/roadrunner-api-dto. On v2.1.0+ prefer roadrunner/api-dto; if you copy a snippet, translate the require line but leave the use statements alone — the namespace did not change.
  • Missing extensions fail late. Without ext-protobuf, serializeToString() throws at runtime, not install time. Add an extension check to CI.
  • ext-grpc is optional but load-bearing. If you don't use the generated clients, you can skip it — but the composer autoloader still resolves the client classes, so any code touching them will fatal.
  • Proto3 defaults look like data. getFoo() on an unset message field returns a default instance, and scalar fields return 0/''/false. Use hasFoo() for message presence and has-less sentinels (e.g. empty string) for scalars. Never assume a returned message means it was set.
  • oneof semantics. Only the last-set member of a oneof survives serialization. If you build a message by setting multiple branches "just in case," you'll silently lose data.
  • Don't edit generated files. Changes vanish on composer update. Regenerate from proto/ if you must patch; better yet, vendor the proto and generate into your own namespace.
  • Debugging. print_r on a DTO dumps internal protobuf plumbing. Use serializeToJsonString() (and mergeFromJsonString()) for human-readable inspection; be aware JSON mapping renames fields to camelCase.
  • JSON mode is lossy for ints/bytes. bytes fields become base64 and int64 may become strings in JSON. For anything that must be exact, stick to binary.
  • Extension points. Add custom messages by copying the .proto files into your repo and generating with protoc-gen-php / protoc-gen-php-grpc into a separate namespace; don't fork this package — and now that the name has changed once, forking is an even worse bet. Wrap the generated classes behind your own interfaces so a future rename or proto change is one adapter away (this release is exactly the scenario that interface insulates you from).
  • Read the README again after upgrading. v2.1.0 also refreshed the docs; if your internal onboarding notes were derived from the old README, re-check the install snippet and any referenced script names.
  • Socket permissions. Unix socket errors (Connection refused, Permission denied) are env issues, not DTO issues — verify RR_RELAY, file mode, and that the RR server is actually running before debugging serialization.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager