URI Templates¶
WellRESTed allows you to register handlers with a router using URI Templates, based on the URI Templates defined in RFC 6570. These templates include variables (enclosed in curly braces) which are extracted and made available to the dispatched middleware.
Reading Variables¶
Basic Usage¶
Register a handler with a URI Template by providing a path that include at least one section enclosed in curly braces. The curly braces define variables for the template.
$router->register("GET", "/widgets/{id}", $widgetHandler);
The router will match requests for paths like /widgets/12
and /widgets/mega-widget
and dispatch $widgetHandler
with the extracted variables made available as request attributes.
To read a path variable, router inspects the request attribute named "id"
, since id
is what appears inside curly braces in the URI template.
// For a request to /widgets/12
$id = $request->getAttribute("id");
// "12"
// For a request to /widgets/mega-widget
$id = $request->getAttribute("id");
// "mega-widget"
Note
Request attributes are a feature of the ServerRequestInterface
provided by PSR-7.
Multiple Variables¶
The example above included one variable, but URI Templates may include multiple. Each variable will be provided as a request attribute, so be sure to give your variables unique names.
Here’s an example with a handful of variables. Suppose we have a template describing the path for a user’s avatar image. The image is identified by a username and the image dimensions.
$router->register("GET", "/avatars/{username}-{width}x{height}.jpg", $avatarHandlers);
A request for GET /avatars/zoidberg-100x150.jpg
will provide these request attributes:
// Read the variables extracted form the path.
$username = $request->getAttribute("username");
// "zoidberg"
$width = $request->getAttribute("width");
// "100"
$height = $request->getAttribute("height");
// "150"
Arrays¶
You may also match a comma-separated series of values as an array using a URI Template by providing a *
at the end of the variable name.
$router->register("GET", "/favorite-colors/{colors*}", $colorsHandler);
A request for GET /favorite-colors/red,green,blue
will provide an array as the value for the "colors"
request attribute.
$colorsHandler = function ($request, $response, $next) {
// Read the variable extracted form the path.
$colorsList = $request->getAttribute("colors");
/* Array
(
[0] => red
[1] => green
[2] => blue
)
*/
};
Matching Characters¶
Unreserved Characters¶
By default, URI Template variables will match only “unreserved” characters. RFC 3968 Section 2.3 defines unreserved characters as alphanumeric characters, -
, .
, _
, and ~
. All other characters must be percent encoded to be matched by a default template variable.
Note
Percent-encoded characters matched by template variables are automatically decoded when provided as request attributes.
Given the template /users/{user}
, the following paths provide these values for getAttribute("user")
:
Path | Value |
---|---|
/users/123 | “123” |
/users/zoidberg | “zoidberg” |
/users/zoidberg%40planetexpress.com | “zoidberg@planetexpress.com” |
A request for GET /uses/zoidberg@planetexpress.com
will not match this template, because @
is a reserved character and is not percent encoded.
Reserved Characters¶
If you need to match a non-percent-encoded reserved character like @
or /
, use the +
operator at the beginning of the variable name.
Using the template /users/{+user}
, we can match all of the paths above, plus /users/zoidberg@planetexpress.com
.
Reserved matching also allows matching unencoded slashes (/
). For example, given this template:
$router->register("GET", "/my-favorite-path{+path}", $pathHandler);
The router will dispatch $pathHandler
with for a request to GET /my-favorite-path/has/a/few/slashes.jpg
$path = $request->getAttribute("path");
// "/has/a/few/slashes.jpg"
Note
Combine the +
operator and *
modifier to match reserved characters as an array. For example, the template /{+vars*}
will match the path /c@t,d*g
, providing the array ["c@t", "d*g"]
.