aboutsummaryrefslogtreecommitdiffstats
path: root/guide/routing.md
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2013-01-18 16:07:38 +0100
committerLoïc Hoguin <[email protected]>2013-01-18 16:07:38 +0100
commit6f552005f274cc6d9056b49dc6c9cee26cb8577f (patch)
tree54a99a0a89b59f7a2a3f6999431606b189165b96 /guide/routing.md
parentefdf3a34333cef12616fcc020d36b64d1bdb11f7 (diff)
downloadcowboy-6f552005f274cc6d9056b49dc6c9cee26cb8577f.tar.gz
cowboy-6f552005f274cc6d9056b49dc6c9cee26cb8577f.tar.bz2
cowboy-6f552005f274cc6d9056b49dc6c9cee26cb8577f.zip
Finish the routing chapter of the guide
Note that this is the new routing not yet available in master. The code should follow in a few days.
Diffstat (limited to 'guide/routing.md')
-rw-r--r--guide/routing.md89
1 files changed, 84 insertions, 5 deletions
diff --git a/guide/routing.md b/guide/routing.md
index 7d6fa41..2970b39 100644
--- a/guide/routing.md
+++ b/guide/routing.md
@@ -90,10 +90,12 @@ PathMatch3 = "/path/to/resource/".
```
Hosts with and without a trailing dot are equivalent for routing.
+Similarly, hosts with and without a leading dot are also equivalent.
``` erlang
HostMatch1 = "cowboy.example.org".
HostMatch2 = "cowboy.example.org.".
+HostMatch3 = ".cowboy.example.org".
```
It is possible to extract segments of the host and path and to store
@@ -115,16 +117,93 @@ segment value where they were defined. For example, the URL
`http://test.example.org/hats/wild_cowboy_legendary/prices` will
result in having the value `test` bound to the name `subdomain`
and the value `wild_cowboy_legendary` bound to the name `hat_name`.
-They can later be retrieved using `cowboy_req:binding/{2,3}`.
+They can later be retrieved using `cowboy_req:binding/{2,3}`. The
+binding name must be given as an atom.
-@todo special binding `'_'`
-@todo optional path or segments
-@todo same binding twice (+ optional + host/path)
+There is a special binding name you can use to mimic the underscore
+variable in Erlang. Any match against the `_` binding will succeed
+but the data will be discarded. This is especially useful for
+matching against many domain names in one go.
+
+``` erlang
+HostMatch = "ninenines.:_".
+```
+
+Similarly, it is possible to have optional segments. Anything
+between brackets is optional.
+
+``` erlang
+PathMatch = "/hats/[page/:number]".
+HostMatch = "[www.]ninenines.eu".
+```
+
+You can also have imbricated optional segments.
+
+``` erlang
+PathMatch = "/hats/[page/[:number]]".
+```
+
+You can retrieve the rest of the host or path using `[...]`.
+In the case of hosts it will match anything before, in the case
+of paths anything after the previously matched segments. It is
+a special case of optional segments, in that it can have
+zero, one or many segments. You can then find the segments using
+`cowboy_req:host_info/1` and `cowboy_req:path_info/1` respectively.
+They will be represented as a list of segments.
+
+``` erlang
+PathMatch = "/hats/[...]".
+HostMatch = "[...]ninenines.eu".
+```
+
+Finally, if a binding appears twice in the routing rules, then the
+match will succeed only if they share the same value. This copies
+the Erlang pattern matching behavior.
+
+``` erlang
+PathMatch = "/hats/:name/:name".
+```
+
+This is also true when an optional segment is present. In this
+case the two values must be identical only if the segment is
+available.
+
+``` erlang
+PathMatch = "/hats/:name/[:name]".
+```
+
+If a binding is defined in both the host and path, then they must
+also share the same value.
+
+``` erlang
+PathMatch = "/:user/[...]".
+HostMatch = ":user.github.com".
+```
Constraints
-----------
-@todo Describe constraints.
+After the matching has completed, the resulting bindings can be tested
+against a set of constraints. The match will succeed only if they all
+succeed.
+
+They are always given as a two or three elements tuple, where the first
+element is the name of the binding, the second element is the constraint's
+name, and the optional third element is the constraint's arguments.
+
+The following constraints are currently defined:
+
+ * {Name, int}
+ * {Name, function, (fun(Value) -> true | {true, NewValue} | false)}
+
+The `int` constraint will check if the binding is a binary string
+representing an integer, and if it is, will convert the value to integer.
+
+The `function` constraint will pass the binding value to a user specified
+function that receives the binary value as its only argument and must
+return whether it fulfills the constraint, optionally modifying the value.
+
+Note that constraint functions SHOULD be pure and MUST NOT crash.
Compilation
-----------