Skip to content

Instantly share code, notes, and snippets.

@gene9
Created August 6, 2014 02:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gene9/7809d5fd928b00fa521c to your computer and use it in GitHub Desktop.
Save gene9/7809d5fd928b00fa521c to your computer and use it in GitHub Desktop.
We need a better syntax for routing. The dispatch list
is both too limited and too inconvenient.
This better syntax will be parsed and converted to a more
efficient form before it is used, therefore the complexity
of the parsing of the routes has no impact on performance.
We accept both strings and binaries.
First we can match normal paths.
"/"
"/cars"
"/cars/that/your/daddy/owned"
We can also bind values.
"/cars/:name"
"/cars/:name/owner"
"/cars/:name/:color"
We can have optional path segment or segments.
"/cars/[that/your/daddy/owned]"
"/cars/[:name]"
"/cars/[:name/owner]"
"/cars/[:name/:color]"
"[/:language]/cars"
We can retrieve the rest of the path by using "[...]".
This must always be the last segment, and this must also
always be inside []s as we don't distinguish empty paths.
This is called the path_info.
"/cars/[...]"
"/cars/[:name/[...]]"
As you can see we can have imbricated optional segments.
"/cars/[:name/[:color]]"
We have the special binding "_" that acts pretty much
like in Erlang, it will match any single segment, just
discarding its value.
"/cars/:_"
"/cars/:_/owner"
"/cars/:_/:color"
"/cars/[:_]"
If a binding is defined twice, the values must be identical.
"/cars/:name/:name"
If a binding is optional, it will only be checked for identity
when it is available.
"/cars/:name/[:name]"
A path rule would look like the following.
{"/cars/:name/:color", Handler, Opts}
We can put additional constraints on bindings. For example
we can check that a value is inside a list of allowed values.
Atom values are allowed here and are converted to the expected
representation before they are used.
{"/cars/:name/:color", [{color, in, [blue, red, pink]}], Handler, Opts}
All this also work for hostnames, with the only difference
being that "[...]" must be set at the beginning, and that
they use dots instead of slashes for segment separators.
"ninenines.eu"
"[www].ninenines.eu"
":name.cardeals.com"
"[...].ninenines.eu"
A leading dot is ignored, the following two rules are equivalent.
"ninenines.eu"
".ninenines.eu"
If a binding happens twice both in the hostname and the path, they
are also checked for identity.
":name.cardeals.com"
"/cars/:name/:color"
A host rule would look like the following.
{":name.cardeals.com", ListOfPathRules}
A host dispatch rule can also have additional constraints on
the bindings. They are valid for the hostname and all the paths
defined. This means that if we were to put a constraint in the
hostname info about the "name" or the "color" bindings in the
previous example, they would also apply to the path.
{":name.cardeals.com", [{color, in, [blue, red, pink]}], ListOfPathRules}
Constraints can be user defined.
{color, fun check_color(C) -> true}
The dispatch list end up being as follow.
[ListOfHostRules].
It must go through a function before it can be used.
cowboy:routing([ListOfHostRules]).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment