Res.Named
Human readable URLs for identifying resources.
This module provides generic support for handling a /name/id[/path]
URL scheme to identify resources.
The stable id
identifier is preceeded by a human readable name
that can change over time without breaking the resource resolution. The name
segment is simply ignored for resolving the resource and redirected to the right one if it doesn't match the name of the ressource identified by id
at the time of resolution.
Let id
and name
be the identifier and name of a given ressource. The URL response scheme should be:
/name/id[/path]
is determined by the resource specific logic./name'/id[/path]
with name'
not an identifier and different from name
is a 301 moved permanently to /name/id[/path]
./name
is either a 404 not found or, if the corresponding id
is easy to find, a 301 moved permanently to /name/id
./id[/path]
is a 301 moved permanently to /name/id[/path]
./s0/s1[/path]
with both s0
and s1
not parsing as identifiers can be used freely without interfering with the scheme.Note that for this to work the name
and id
syntax must be distinguishable unambiguously.
The Named.resolve
function handles point 2 and 4 in a generic manner. The Named.name_of_string
function provides a (non-injective) naming scheme for arbitrary strings that is human readable, compatible with URL path segment syntax and unambiguously distinguishable from non-negative numerical identifers (e.g. Res.Id
).
val resolve :
?eq:('name -> 'name -> bool) ->
get_res:('id -> ('res, Webs.Http.Response.t) Stdlib.result) ->
res_name:('res -> 'name) ->
res_url:('name -> 'id -> string) ->
req_name:'name option ->
req_id:'id ->
unit ->
('res, Webs.Http.Response.t) Stdlib.result
resolve ~eq ~get_res ~res_name ~res_url ~req_name ~req_id ()
implements the 301 redirection logic spelled out in the preamble of this module.
Given a request's parsed identifier req_id
and name req_name
(if any):
get_res req_id
is Error _
this is returned by the function.get_res req_id
is Ok res
, let n
be res_name res
.req_name
is None
a 301 moved permanently Error _
to res_url n req_id
is returned.req_name
is Some n'
and eq n n'
is false
a 301 moved permanently Error _
to res_url n req_id
is returned.Ok res
is returned.eq
defaults to Stdlib.(=)
. res_url
must return a value suitable for the Webs.Http.Headers.location
header.
val name_of_string : string -> name
name_of_string s
maps s
to a name that can be used as a human readable URL path segment. It transforms s
to a sequence of '-'
separated tokens. A '-'
is appended to the empty string and to sequences of US-ASCII digits only so that they can be distinguished from numerical identifiers (e.g. Res.Id
). More precisely this:
'-'
.'-'
s and compresses consecutive '-'
."-"
if the result is empty or only has US-ASCII digits.The function is not injective. It is idempotent and preserves all non US-ASCII UTF-8 characters. It is meant to be applied before percent encoding.