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

Uuid Normalizer Laravel Package

gbprod/uuid-normalizer

A Symfony Serializer normalizer for Ramsey UUIDs. Install via Composer, register UuidNormalizer and UuidDenormalizer as serializer.normalizer services, and serialize or deserialize UUIDs without "Not a time-based UUID" errors. Requires PHP 7.4+.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Scope is deliberately tiny: two classes (UuidNormalizer, UuidDenormalizer) implementing symfony/serializer's NormalizerInterface / DenormalizerInterface, mapping Ramsey\Uuid\UuidInterface ↔ canonical string. No service provider, no config, no facade, no Laravel package discovery, no Artisan surface.
  • Fit hinges on one architectural fact: does the application serialize/deserialize DTOs through symfony/serializer? Vanilla Laravel (Eloquent toArray, JsonResource, FormRequest, Cast) does not — so baseline value for a stock Laravel app is approximately zero, and adopting this package implicitly means adopting symfony/serializer to solve a UUID problem.
  • Where symfony/serializer is already in the stack (API Platform, a hexagonal ports-and-adapters boundary layer, CQRS/queue payloads, laravel-data with its serializer bridge), it closes a real and well-documented gap: ObjectNormalizer cannot handle Ramsey UUIDs and throws the "Not a time-based UUID / UnsupportedOperationException" class of errors the README cites.
  • Overlap risk: Symfony 6.2+ ships UidNormalizer for symfony/uid. This package is only relevant when Ramsey is the UUID of record — which it is in Laravel, since Str::uuid() returns a Ramsey\Uuid\UuidInterface. Confirm no dual UUID library situation.
  • License is WTFPL: permissive in practice but not OSI-approved, and it reliably flags in enterprise OSS scans. Expect legal/procurement friction wildly disproportionate to the ~100 lines of code involved.

Integration feasibility

  • Mechanically trivial: composer require, then compose the normalizer chain explicitly (or tag serializer.normalizer if a bridge container is in use). Realistically half a day plus tests.
  • No framework coupling — equally usable in the HTTP layer, a queue worker, or a shared internal package. That portability is a genuine plus for multi-runtime estates.

Technical risk

  • Bus factor 1, 30 stars, zero dependents: essentially no community validation and no evidence of production use at scale. The mitigating fact is that the entire surface is reproducible in-house in under a day — treat it as adopt-with-vendored-fallback, not adopt-and-depend.
  • Version drift: ramsey/uuid v5 and symfony/serializer v8 compatibility is unproven. Pin and test.
  • Behavioral gaps the README does not address: malformed-input exception mapping, null/optional UUID properties, and binary vs canonical string persistence. These must be proven by tests, not assumed.

Key questions

  • Where exactly does symfony/serializer sit in our request, response, and queue paths today? If the answer is "nowhere," this package is a non-starter.
  • Are UUIDs char(36) or binary(16) in persistence, and which representation is intended to cross the wire?
  • Do we need UUIDv7 (Ramsey 4.7+)? Does the denormalizer preserve concrete subtype where downstream code depends on it?
  • Is a WTFPL third-party dependency acceptable, or do we vendor the two classes?
  • Who owns the round-trip contract test, and where does it live in CI?

Integration Approach

Stack fit

  • Target: PHP 8.1+, Laravel 10–12, ramsey/uuid ^4, symfony/serializer ^6/^7. Nothing Laravel-specific is provided — registration is entirely our code.
  • Recommended shape: a dedicated SerializerServiceProvider (or App\Support\SerializerFactory) that composes the chain explicitly — normalizers [UuidNormalizer, DateTimeNormalizer, ObjectNormalizer], denormalizers [UuidDenormalizer, …]. Normalizer ordering is the entire integration; get it wrong and the original exception returns intermittently.
  • If laravel-data is the DTO layer, do not add this at all — use a custom DataTransformer/cast. That is the idiomatic path and avoids a second serialization stack in the same request.

Migration path

  • Phase 0 (spike): one endpoint, one DTO with a UuidInterface property, round-trip both directions, assert exact string format, assert 422 on malformed input.
  • Phase 1 (decision gate): if the spike requires introducing symfony/serializer where none existed, stop. The cost of that adoption dwarfs the benefit; a 40-line Laravel cast or transformer solves the same problem with none of the dependency surface.
  • Phase 2 (serializer already present): register globally, delete ad-hoc ->toString() / Uuid::fromString() mappers at the boundary, consolidate.
  • Fallback path: vendor the two classes into App\Serialization under our namespace. Removes the dependency and the license question at effectively zero maintenance cost.

Compatibility

  • Narrow by design: Ramsey UuidInterface only — no symfony/uid, no generic string identifiers, no composite keys.
  • Coexistence hazard if both UUID libraries are installed: verify (not assume) supports*() precedence against Symfony's UidNormalizer.
  • Already-queued or cached payloads serialized before adoption may not round-trip; plan a queue drain or version the payload shape.

Sequencing

  1. Inventory serialization surfaces: HTTP resources, jobs, cache, webhooks, third-party SDK clients.
  2. Spike one low-traffic surface; observe ordering behavior empirically.
  3. Contract tests: v4 and v7, nil UUID, uppercase, braces/URN forms, malformed input, null property.
  4. Register in a single provider; gate behind config if touching high-traffic endpoints.
  5. Decide depend vs. vendor in the same review, and record the decision.

Operational Impact

Maintenance

  • Expected code churn is near zero; low upstream activity is a signal problem rather than a volume problem. Pin an exact version, add to the dependency-watch list, and re-evaluate on each ramsey/uuid or symfony/serializer major.
  • Negligible security surface — no I/O, no structured deserialization beyond UUID parsing. The realistic risk is silent behavior change, not a CVE.
  • License scanning is the single largest recurring overhead; one-time cost, but it recurs on every policy re-scan.

Support

  • Single maintainer, 30 stars, zero dependents → no Stack Overflow corpus. Internal documentation is mandatory: why the dependency exists, where it is registered, the ordering rule, and the canonical string format.
  • On-call runbook entry: "500 with UUID exception" → check normalizer registration and request validation first, not the database.

Scaling

  • Effectively free: pure per-property function, microseconds per request, no DB, cache, network, or memory implications. It may reduce payload size by preventing binary UUIDs leaking into JSON.
  • The only scale-adjacent concern is consistency: once UUIDs are string-normalized at the boundary, every consumer relying on the old representation breaks at the same instant and at full traffic. This is a coordinated rollout, not a gradual one.

Failure modes

  • Malformed input → uncaught exception → 500 instead of 422. Highest-probability production incident; mitigate with request-level exception mapping plus negative tests.
  • Normalizer ordering regression: ObjectNormalizer (or UidNormalizer) claims UuidInterface first; symptom is the original "Not a time-based UUID" error resurfacing after an unrelated composer update.
  • Representation mismatch: binary(16) column emitted as canonical string, or the reverse — produces valid-looking but wrong identifiers that propagate downstream and are hard to detect after the fact.
  • Null/optional UUID properties: governed by Serializer config (skip_null_values), not by this package; test explicitly rather than reasoning about it.
  • Version drift: ramsey/uuid v5 or symfony/serializer v8 returns to a hard failure with no upstream fix timeline.
  • Payload compatibility: pre-adoption serialized jobs/cache entries may fail to denormalize post-adoption.

Ramp-up

  • ~1 hour for a mid-level engineer to read both classes and internalize the ordering rule; ~1 day including provider wiring and contract tests.
  • Knowledge concentration is the real cost: whoever wires it owns it. Capture the ordering rule and the string-format decision in an ADR so the next engineer does not rediscover them under incident pressure.
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.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator