-
Notifications
You must be signed in to change notification settings - Fork 2
The 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
.
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);
});
}
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);
});
For more complex applications, you'll probably want to use our Controller API. The Controller API allows you to implement more complex behaviours.
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).
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);
}
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;
}
// ...
};
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 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);