Skip to content

inaka/cowboy-trails

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stories in Ready

cowboy-trails

Cowboy routes on steroids!

Contact Us

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.

Why Cowboy Trails?

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.

How to Use it?

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.

Example

For more information about cowboy_trails, how to use it and the different functions that it exposes, please check this Example.