Skip to content
Plaristote edited this page Sep 14, 2017 · 4 revisions

Router

The router's job is to read a request URI, and find a function which can take care of it. You may define those function in the Router::initialize method in app/routes.cpp.

Route matching

The router allow you to define routes, and match them to functors. With some sugar on top, it can also match route to controller methods. However, we'll start with the most simple use case, which is a simple lambda handler displaying "Hello World !" to the user:

#include <crails/router.hpp>

using namespace Crails;
using namespace std;

void Router::initialize()
{
  match("GET", "/hello", [](Params& params, function<void(DataTree)> callback)
  {
    DataTree response;

    response["headers"]["Content-Type"] = "text/plain";
    response["body"] = "Hello World !";
    callback(response);
  });
}

Route parameters

Sometimes, you'll want your route to contain parameters. The route matcher can detect parameters in your route, and forward them to you using the Crails::Params object:

match("GET", "/resource/:resource_id/nested/:id", [](Params& params, function<void(DataTree)> callback)
{
  DataTree response, response_body;

  response_body["resource_id"] = params["resource_id"].as<long>();
  response_body["nested_id"]   = params["id"].as<long>();
  response["headers"]["Content-Type"] = "application/json";
  response["body"] = response_body.as_data().to_json();
  callback(response);
});

Controllers

For more complex applications, you'll probably want to use our Controller API. The Controller API allows you to implement more complex behaviours.

SetRoute

SetRoute is a macro that generates a lambda for the router that forwards the request to your controller. It is that lambda that will:

  • create an instance of your controller
  • execute the controller's initialize method
  • execute your controller method (action method)
  • execute the controller's finalize method
  • return the Controller's response attribute

Note that if you set response["status"] in the constructor, the request will be considered finished, and none of the following methods will be run. However, if you set response["status"] in the controller's initialize method, only the action's method will be skipped (the finalize method will be called).

How to use SetRoute

Here's how you'd use SetRoute to reproduce the behavior of our first Hello World example:

class HelloController : public Crails::Controller
{
public:
  HelloController(Crails::Params& params) : Controller(params) {}

  void show()
  {
    response["headers"]["Content-Type"] = "text/plain";
    response["body"] = "Hello world !";
  }
};

void Router::initialize()
{
  SetRoute("GET", "/hello", HelloController, show);
}
Controller data provided by the router

The router also provides some more parameters for your controller to know which action is being run. These variables are accessible through the params["controller-data"] object:

class HelloController : public Crails::Controller
{
public:
  HelloController(Crails::Params& params) : Controller(params)
  {
    std::cout << "Controller name: " << params["controller-data"]["name"].as<string>() << std::endl;
    std::cout << "Controller method: " << params["controller-data"]["action"].as<string>() << std::endl;
  }

  // ...
};
Asynchronous controllers

By default, Crails Controllers work in a synchronous way. If you want to implement asynchronous controllers, you will need to use SetAsyncRoute instead of SetRoute. Here's how you'd use SetAsyncRoute to reproduce the behavior of our first Hello World example:

class AsyncHelloController : public Crails::Controller
{
public:
  AsyncHelloController(Crails::Params& params) : Controller(params) {}

  void show(std::function<void()> done)
  {
    response["headers"]["Content-Type"] = "text/plain";
    response["body"] = "Hello world !";
    done();
  }

  // The initialize and finalize methods also take a std::function as parameter
  // void initialize(std::function<void()> done) { done(); }
  // void finalize(std::function<void()> done) { done(); }
};

void Router::initialize()
{
  SetAsyncRoute("GET", "/hello", AsyncHelloController, show);
}

Crudify

Crudify is a shortcut to generate CRUD-compliant routes to a resource:

  Crudify(users, UsersController)
  // Generates the follwing:
  SetRoute("GET",    "/users",          UsersController, index);
  SetRoute("GET",    "/users/:id" ,     UsersController, show);
  SetRoute("POST",   "/users",          UsersController, create);
  SetRoute("PUT",    "/users/:id",      UsersController, update);
  SetRoute("DELETE", "/users/:id",      UsersController, destroy);