laravel-json-api/hashids
Adds Hashids support to Laravel JSON:API, encoding resource IDs into short, obfuscated strings and decoding them on request. Configure salt, length, and alphabet while keeping numeric database keys hidden behind spec-compliant JSON:API routes and relationships.
Architecture fit. The package occupies exactly one seam — the resource-ID encoder contract in laravel-json-api — which is the correct place for this concern to live. From a program perspective that containment is the main attraction: the decision lands on a single interface rather than being smeared across controllers, serializers, form requests, and models. The fit is nevertheless conditional on a commitment that is larger than the package itself: the organization must already have standardized on laravel-json-api as its API layer. If that commitment has not been made, this package has no delivery value irrespective of its quality. The TPM should treat "are we a JSON:API shop?" as the gating question, and "do we want hashed IDs?" as the downstream one.
Integration feasibility. Mechanically small: a composer require, a publishable config file, service-provider registration, and per-schema encoder wiring. The realistic effort is not installation but verification. Encoding must be proven correct across resource objects, relationship identifiers, relationship endpoints, create and update responses, pagination links, and error documents — a finite, enumerable test matrix, but one that must be scoped as work rather than assumed as a side effect. The unknown that has to close before commitment is the version matrix: PHP, Laravel, laravel-json-api, and the underlying hashids/hashids library. With 5 stars and 0 dependents, that matrix has almost certainly not been validated by anyone outside the author, so a timeboxed spike is mandatory rather than prudent.
Technical risk. Three risks belong on the delivery plan. First, ecosystem risk — five stars, zero dependents, single-maintainer bus factor. The correct framing is that this is source we adopt, not a library we rely on; at roughly fifty lines of adapter, vendoring or inlining is a defensible half-day of engineering rather than a strategic dependency. Second, contract risk — resource IDs are the most externally visible artifact in an API. Once clients, bookmarks, shared links, support macros, and partner integrations bind to a hash format, changing the salt, minimum length, or alphabet becomes a breaking change requiring versioning and deprecation. It is a one-way door, and it is materially cheaper to walk through before public launch than after. Third, misunderstanding risk — Hashids is reversible obfuscation; the salt is the entire secret. The most likely organizational failure is that some planning or review document describes this as a security control, after which authorization reviews, pen tests, and incident response get calibrated against a property the system does not have. That is a communications deliverable the TPM owns, not a code deliverable.
Key questions.
laravel-json-api already committed, or is this the decision that commits us?.env?Stack fit. Strong for an existing Laravel service on laravel-json-api with string-typed resource IDs that wants to keep integer primary keys internally for index size and write performance. Weak for mixed API surfaces — some JSON:API, some hand-rolled REST, some GraphQL — because the encoder governs only one of them, and inconsistent ID formats across surfaces are worse for clients than uniformly sequential IDs. Also a poor fit where multiple services must independently encode or decode the same record: encoding has to be centralized, or two services with divergent salts will disagree about which public ID belongs to which row.
Migration path. Stage it as a bounded pilot, not a rollout. One low-risk resource, non-production first, with explicit acceptance criteria: encoded IDs round-trip, relationships resolve, route model binding still works, authorization policies behave identically, and the test suite asserts the ID format. Then a single production resource behind an agreed rollback (a config flip back to numeric IDs) before broadening. Do not sequence this behind a large API versioning effort, but do not run it in parallel with one either — the ID format decision should land inside whatever version boundary the API program already has, so the breaking change is absorbed once.
Compatibility. Treat the version matrix as a gate, not a caveat. Confirm PHP, Laravel, and laravel-json-api constraints against the specific tag being installed, and establish whether this is a first-party companion to laravel-json-api or an independent adapter — the answer determines the support story and the likelihood of it tracking framework releases. Verify behavior under config:cache: a salt that resolves differently in cached versus uncached configuration is a production-only failure that will not surface in local testing, and it is exactly the class of bug a low-signal dependency never gets patched for.
Sequencing.
Maintenance. Low code surface, elevated stewardship burden. The honest posture is: we own this, upstream may not. Budget a fork-or-inline contingency and name the engineer against it. Ongoing work is small — dependency bumps, salt and config review, ID-stability regression tests — but it lands on whoever owns the API platform and must appear in their capacity plan, or it resurfaces six months later as a mysterious upgrade blocker.
Support. External support is effectively absent, so an internal runbook is a delivery requirement rather than documentation polish. It must state how IDs are encoded, where the salt lives, that rotation invalidates every issued ID and every cached or bookmarked URL, and that authorization lives in policies rather than in ID opacity. Support and customer success also need a short brief: public IDs are strings, they are not numbers, and they cannot be parsed or incremented. Without that brief, the first ticket about a "broken" link becomes an engineering incident.
Scaling. Encoding and decoding cost is negligible and will not be a throughput concern at any realistic volume. The scaling issues are operational: consistent encoding across instances and environments, cache-key redesign where public IDs replace numeric keys, search and indexing by public ID, analytics joins that previously keyed on integers, and the discipline of never emitting both numeric and encoded IDs from different surfaces. Each is an owner-and-checklist problem, not a performance problem.
Failure modes. Enumerate them up front so they are recognized rather than diagnosed. Salt drift between environments breaks every stored link. Salt rotation invalidates all issued IDs at once. config:cache divergence produces production-only decode failures. A framework upgrade silently changes encoder resolution. Clients parse IDs and treat segments as meaningful, which turns an internal change into a client-visible break. Someone describes the mechanism as security, and access-control review is weakened as a result. Two services encode the same record differently. Every one of these is cheap to prevent and expensive to discover.
Ramp-up. One engineer can absorb this in under a day — it is a config file and an interface registration. The ramp-up that actually matters is organizational: product needs to understand and sign the opaque-ID contract, support needs the "IDs are not numbers" brief, and the API platform owner needs the runbook and the fork contingency. Plan for a week of elapsed coordination around a half-day of engineering, and treat the coordination as the real deliverable.
How can I help you explore Laravel packages today?