Ranked Request-Pattern Router
Problem
Design RankedRequestPatternRouter to store ranked route patterns and resolve each concrete request path to a destination. Calls use one sequential router instance.
Requirements
- Append a new pattern.
addRoute places a previously unseen exact pattern after all existing registrations.
- Replace a duplicate destination. Adding an identical existing pattern replaces that registration's destination.
- Preserve duplicate rank. Replacing an identical pattern keeps its original first-registration rank.
- Require equal segment counts. A pattern can match only a request path with the same number of segments.
- Match literals exactly. A literal pattern segment matches only an identical request-path segment.
- Match one wildcard segment. A pattern segment equal to
* matches exactly one non-empty request-path segment.
- Match one parameter segment. A valid named parameter such as
:teamId matches exactly one non-empty request-path segment. Its value is not returned.
- Choose the earliest match.
callRoute returns the destination of the matching pattern with the earliest first-registration rank. A later literal pattern does not outrank an earlier placeholder pattern.
- Report an unmatched path. A valid request path that matches no pattern returns
"NOT_FOUND".
- Reject an invalid pattern.
addRoute raises the runtime's standard invalid-argument exception when pathPattern does not follow the route-pattern grammar.
- Reject an empty destination.
addRoute raises the runtime's standard invalid-argument exception when destination is empty.
- Reject an invalid request path.
callRoute raises the runtime's standard invalid-argument exception when requestPath does not follow the concrete-path grammar.
- Preserve rejected additions. If
addRoute raises an invalid-argument exception, every registration, destination, and rank remains unchanged.
API
| Signature | Returns | Behavior |
|---|
RankedRequestPatternRouter() | Not applicable | Creates an empty router. |
addRoute(pathPattern: string, destination: string) | void | Registers the pattern and destination according to the requirements above. |
callRoute(requestPath: string) | string | Resolves the request path according to the requirements above. |
Examples
| Step | Operation | Result |
|---|
| 1 | addRoute("/teams/*", "wild") | void |
| 2 | addRoute("/teams/:teamId", "parameter") | void |
| 3 | addRoute("/teams/core", "literal") | void |
| 4 | callRoute("/teams/core") | "wild" |
| 5 | addRoute("/teams/*", "wild-v2") | void; the pattern keeps its rank |
| 6 | callRoute("/teams/core") | "wild-v2" |
| Step | Operation | Result |
|---|
| 1 | addRoute("/users/:id/profile", "profiles") | void |
| 2 | callRoute("/users/u1/profile") | "profiles" |
| 3 | callRoute("/users/u1") | "NOT_FOUND" |
Constraints
- A path pattern or request path contains one or more non-empty segments, starts with exactly one
/, and has no trailing /.
- A literal segment contains only ASCII letters, decimal digits, dots, underscores, or hyphens.
- A placeholder is exactly
* or :name. A parameter name starts with an ASCII letter and otherwise contains only ASCII letters, decimal digits, or underscores.
- A request path contains only literal segments. Placeholders are valid only in path patterns.
- A destination is any non-empty ASCII string.
"NOT_FOUND" is a valid destination. Returned strings are compared exactly.
- Inputs are ASCII strings. The router does not process query strings, fragments, percent encoding, or path normalization.
Notes
None.