Cowboy routes on steroids!
For questions or general comments regarding the use of this library, please use our public hipchat room.
If you find any bugs or have a problem while using this library, please open an issue in this repo (or a pull request :)).
And you can check all of our open-source projects at inaka.github.io.
Cowboy-Trails enables you to:
-
Add information to
cowboy
routes, which can be used later to interact with the server with a higher abstraction level. -
Define the server routes directly within the module that implements them.
The first use case for cowboy_trails
is to compile cowboy
routes.
Normally with cowboy
you compile routes in this way:
Routes = [{'_',
[ {"/resource1", resource1_handler, []}
, {"/resource2/[:id]", resource2_handler, []}
]
}
],
cowboy_router:compile(Routes),
Trails is also fully compatible with cowboy
routes, so you can pass the same
routes in order to be processed by trails:
trails:compile(Routes),
So far seems like there is not any difference right? But the most common case
with cowboy
is that you usually work with a single host, even though you're
required to keep defining the host parameter within the routes ([{'_', [...]}]
).
Well, with trails you have another useful function to compile single host routes:
%% You only define the routes/paths
Routes = [ {"/resource1", resource1_handler, []}
, {"/resource2/[:id]", resource2_handler, []}
],
trails:single_host_compile(Routes),
Now, let's suppose that you want to add additional information (metadata) to cowboy routes related with the semantics of each HTTP method.
Metadata = #{put => #{description => "PUT method"},
post => #{ description => "POST method"},
get => #{ description => "GET method"}},
Trail = trails:trail("/",
cowboy_static,
{private_file, "index2.html"},
Metadata,
[]),
%% You can later retrieve the metadata:
Metadata = trails:metadata(Trail),
This can be used later to generate documentation related to each endpoint.
Normally, when you work with cowboy
you have to define all routes in one place,
for example like this:
Routes =
[{'_',
[ {"/", cowboy_static, {file, "www/index.html"}}
, {"/favicon.ico", cowboy_static, {file, "www/assets/favicon.ico"}}
, {"/assets/[...]", cowboy_static, {dir, "www/assets"}}
, {"/game/:game_id", cowboy_static, {file, "www/game.html"}}
, {"/api/status", spts_status_handler, []}
, {"/api/games", spts_games_handler, []}
, {"/api/games/:game_id", spts_single_game_handler, []}
, {"/api/games/:game_id/serpents", spts_serpents_handler, []}
, { "/api/games/:game_id/serpents/:token"
, spts_single_serpent_handler, []
}
, {"/api/games/:game_id/news", lasse_handler, [spts_news_handler]}
]
}
],
Dispatch = cowboy_router:compile(Routes),
But now with trails
you're able to define the routes on each resource handler,
and your handler must implement the callback trails/0
and return the specific
routes for that handler. To better understanding, in the test
folder you will
find some examples, e.g.: trails_test_handler.
Once you have implemented trails/0
callback on your handlers, you can do
something like this:
Handlers =
[ spts_status_handler
, spts_games_handler
, spts_single_game_handler
, spts_serpents_handler
, spts_single_serpent_handler
, spts_news_handler
],
Trails =
[ {"/", cowboy_static, {file, "www/index.html"}}
, {"/favicon.ico", cowboy_static, {file, "www/assets/favicon.ico"}}
, {"/assets/[...]", cowboy_static, {dir, "www/assets"}}
, {"/game/:game_id", cowboy_static, {file, "www/game.html"}}
| trails:trails(Handlers)
],
trails:single_host_compile(Trails),
In this way each handler keeps their own routes, as it's supposed it should be, and then you can merge them easily.
For more information about cowboy_trails
, how to use it and the different
functions that it exposes, please check this Example.