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

Json Codec Laravel Package

wikimedia/json-codec

A PHP library from Wikimedia for converting objects to and from JSON using schemas, with validation, custom codecs, and typed deserialization to keep JSON handling consistent and safe.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require wikimedia/json-codec. The GitHub repo is only a Gerrit mirror; Composer resolves through Packagist, so don't use a vcs repository entry pointed at GitHub. It requires PHP 8.1+ and ext-json.
  • It is a library, not a Laravel package — there is no service provider, no config file, no facade, no validation. You wire it yourself.
  • Read in this order: README.md → src/JsonCodec.php (the entry point and registry) → src/JsonCodecable.php / src/JsonCodecableTrait.php (how your DTOs opt in) → src/JsonClassCodec.php (how to serialize classes you don't own).
  • First use case: a typed DTO for a third-party JSON API or queue payload where you want round-trip fidelity and explicit class tags, e.g. $dto = $codec->deserialize($response->body(), OrderPayload::class);
use Wikimedia\JsonCodec\JsonCodec;
use Wikimedia\JsonCodec\JsonCodecable;
use Wikimedia\JsonCodec\JsonCodecableTrait;

final class Money implements JsonCodecable {
    use JsonCodecableTrait;

    public function __construct(
        public int $amount,
        public string $currency,
    ) {}
}

$codec = new JsonCodec();
$json  = $codec->serialize( new Money( 1250, 'EUR' ) );
$money = $codec->deserialize( $json, Money::class );

If that round-trip works, you understand the library. If you find yourself fighting it to make it fit Eloquent models, stop — it isn't the right tool.

Implementation Patterns

DTO-first, not model-first. Keep the codec at the edges: HTTP clients, queue payloads, cache values, webhook bodies. Map explicitly to and from Eloquent models. Do not add JsonCodecable to models or let it replace JsonResource.

Bind a singleton in a service provider.

$this->app->singleton( JsonCodec::class, function () {
    $codec = new JsonCodec();

    // Stable wire names decoupled from PHP class names.
    $codec->addClassAlias( 'OrderPayload', OrderPayload::class );

    // Custom codecs for vendor value objects.
    $codec->addCodec( Money::class, new MoneyCodec() );

    return $codec;
});

Then inject JsonCodec into the few services that need it. Reflection is not free; don't construct a codec per request or per row.

Custom codecs for classes you can't modify. Implement JsonClassCodec and register it with JsonCodec::addCodec(). This is the pattern for DateTimeImmutable, money libraries, enums, and any vendor value object. It's also where you should centralize casts and scalar coercion.

Polymorphism via aliases, not FQCNs. Store a stable alias per class so renaming or moving a class in your codebase doesn't invalidate cached or queued JSON. Treat the alias map like a database schema and version it alongside your code.

Lists and generics. The trait needs type information for array members; express it with typed properties and docblocks/attributes so it knows what to instantiate. For heterogeneous lists, emit a per-element type hint and deserialize into a common interface backed by aliases.

Laravel integration points:

  • Outbound HTTP: Http::withBody($codec->serialize($dto), 'application/json')->post(...). Inbound: $codec->deserialize($response->body(), Foo::class).
  • Queues: serialize to a string in the job payload and deserialize in handle(), so the queue never sees PHP objects.
  • Cache: store the string, not the object — portable, inspectable with redis-cli, and free of unserialize risk.
  • Validation: combine with Form Requests. The codec validates structure, not business rules.

Testing. Write round-trip tests (deserialize(serialize($x)) == $x) and snapshot tests on the JSON string. Snapshot the alias names too — that's your wire contract, and it's the thing that will silently break.

When not to use it. Simple toArray() responses (native JsonSerializable is enough), Eloquent resources (JsonResource), or anything already covered by spatie/laravel-data or Symfony Serializer. The value here is explicit, safe, round-trippable type tags — if you don't need that, you're paying complexity for nothing.

Gotchas and Tips

  • License is GPL-2.0. This is the biggest practical concern for a Laravel app. GPL is copyleft; if you distribute the app (and, under some interpretations, for SaaS), get legal review. Many teams will prefer MIT/BSD serializers purely on licensing. Don't let it slip in as a transitive dependency unnoticed.
  • It's a Gerrit mirror. Issues and patches go to Phabricator/Gerrit, not GitHub. With ~1 star and 0 dependents you are largely on your own: pin the version, and expect no Laravel-specific fixes or responsiveness.
  • Deserialization is a trust boundary. Instantiating classes from attacker-controlled JSON is dangerous, in the same family as unserialize() object injection. Allowlist only the aliases you control; never let arbitrary input select the class. Validate and reject unknown aliases before deserializing.
  • Class names in JSON are a schema. Renaming a class or property breaks stored payloads, queued jobs, and caches. Aliases plus explicit toJsonArray() / newFromJsonArray() overrides are your migration tool; plan for it.
  • Reflection and typed properties. Uninitialized typed properties can blow up in toJsonArray(); nullable properties need explicit handling. Give every property a default or set it in the constructor, and keep property visibility consistent.
  • json_encode flags aren't yours to set. You get the library's output. If you need JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, or key ordering, you're post-processing or decode/re-encoding — which defeats part of the point. Don't rely on the codec's string being byte-stable for signing or hashing; canonicalize explicitly.
  • Scalar coercion surprises. 1250 vs "1250" and int/float ambiguity bite in custom codecs. Cast defensively and test both shapes.
  • Debugging tips. dd($dto->toJsonArray($codec)) before serializing (the trait makes this easy); wrap deserialize() in try/catch and convert failures to a domain InvalidPayloadException so 500s don't leak internals; log the raw JSON plus the expected class on failure.
  • Extension points to know. JsonCodecableTrait for defaults (override for custom keys), JsonClassCodec for external classes, class aliases for stable wire names, and subclass registration for polymorphic hierarchies.
  • Performance. Cache the singleton; avoid serializing large collections element-by-element when a single custom codec can do one array pass. Measure if this is on a hot path.
  • Reality check. For most Laravel apps this is over-engineering. Reach for it when you genuinely need typed, round-trip serialization across a boundary you don't control — and when GPL-2.0 is acceptable to your legal team.
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