guzzlehttp/uri-template
Expands RFC 6570 URI templates into concrete URI strings in PHP, turning templates like /users/{id}{?tab} into real paths with query strings from an array of values.
sprintf-style path building, and ad-hoc query encoding with a spec-backed RFC 6570 expander. That is a buy decision with a very small footprint: one static call, MIT license, maintained under the Guzzle organization. The alternative — writing a partial, subtly wrong expander in-house — is a recurring source of encoding bugs (double-encoded query keys, 0 values dropped, Unicode prefixes split mid-codepoint) that this library has already fixed and regression-tested.Link headers, OpenAPI links and server-variable definitions, WebFinger, or pagination "next" links — you need a template expander, not a URL builder. This is the enabling dependency for "follow the links the API gives us" designs, which materially reduce coupling to hardcoded endpoint paths.InvalidArgumentExceptions rather than half-valid URLs sent to a third party.Adopt when:
{var} / {?var} RFC 6570 syntax and you need to fill those in at runtime.>=7.4,<8.6; v2.0.1 adds PHP 8.6 support). If you are pinned below 7.4, the v1.0 maintenance line (PHP >=7.2.5) is still supported.guzzlehttp/guzzle is the starting point and this comes along the dependency graph; install guzzlehttp/uri-template directly only when expansion is the actual need.UriTemplate::expand() only), previously-tolerated invalid templates now throw, and previously-silent coercions (booleans, floats, nulls in composites) now have defined behavior. Budget a test pass over every stored template.Look elsewhere when:
style/explode/allowReserved serialization rules diverge from RFC 6570 in several places. Use a dedicated OpenAPI request builder rather than assuming this covers it; use this only for the parts of the spec that genuinely are URI templates.http_build_query() or PSR-7's Uri with a query builder is simpler and has no new dependency. Reach for this package when the template itself is data — configured, generated, or received from a server.Diligence items before committing:
composer why / dependency graph rather than trusting the metric, because it materially changes the "is this maintained?" conversation.^2.0 and track patch releases; the 2.x line is where correctness fixes land.For executives (one paragraph): We are proposing a small, MIT-licensed, standards-based PHP dependency that builds URLs from templates instead of from string concatenation. It is one function call, it is maintained by the Guzzle organization, and it removes a whole class of integration defects — malformed query strings, mis-encoded international characters, dropped zero values, broken pagination links — that currently surface as customer-visible failures and support tickets. It supports our direction of following links that APIs advertise rather than hardcoding endpoints, which reduces the cost of every future integration. Cost is effectively zero: no infrastructure, no vendor contract, no lock-in. The one real cost is a one-time audit of existing templates when we move to the current major version, because it now rejects malformed input loudly instead of guessing. Recommendation: adopt at the current major, pin the version, and revisit commercial support only if it lands on a critical path.
For engineering leads: Single-purpose library — UriTemplate::expand($template, $variables) — with a strict v2 contract. It validates template syntax, variable names and modifiers, and UTF-8 in values and map keys before producing any output, so failures arrive as InvalidArgumentException at a known point rather than as a partially-built URL. Behavior is fully specified for edge cases we would otherwise argue about: dense arrays expand as lists and sparse/mixed-key arrays as maps, booleans are 1/0 at every nesting level, non-finite floats throw, floats never pick up a locale decimal separator, and prefix modifiers count Unicode code points rather than bytes. UriTemplate is non-instantiable and rejects PHP serialization. Requires PHP ≥ 7.4; 2.0.1 covers PHP 8.6. If we are on 1.x, the upgrade is mechanical but not invisible — see the v2.0.0 changelog for the full behavior deltas. Not a router: it expands templates, it does not match incoming URIs. And it does not validate that the resulting URL is safe to call, so any untrusted template or variable input still needs our own scheme/host allow-listing.
How can I help you explore Laravel packages today?