Skip to content

Controller Tutorial

Jacob Jensen edited this page Oct 13, 2017 · 7 revisions

Here is a tutorial on how to use controllers and route mapping.

This example focuses mostly on controllers for websites, however using them for webservices are pretty much the same, except for no view support.

1. Setting up a controller

Controllers are simply classes that inherit from the Controller class. To create a controller, one must create a new class that inherits from that. For websites you must specify a generic type for views.

final class MyController(TView) : Controller!TView {
}

After v0.4.0

final class MyController(TView) : Controller!(TView,MyController!TView) {
}

The entry route for a controller is always the view that it inherits. For webservices it's of course the name given to the controller. This means that controllers for websites are more dynamically, as they aren't defined by themselves, but by views, where as controllers for webservices are always stand-alone.

2. The constructor

After declaring a controller, a constructor must be setup.

The constructor for websites takes in a view, where the constructor for webservices takes a request, response and a route.

The constructor is called for every request and can be used to handle connections before actions.

3. Routing

In the constructor you usually map actions.

There are 3 types of actions that can be mapped to routes.

Default actions, mandatory actions and regular actions. A controller can only have one default action, which is the action called when no action has been specified, a mandatory action is an action that is always called and must go through successfully for the actual action to be executed. Mandatory actions can be used for authentication, validation etc. and can only be mapped once just like default actions. At last there is the regular actions, which are just actions mapped to a specific action route.

Routing for controllers are as following:

/{controller-route|view-route}/{action}/{params}

Note: Instead of using params, you can use query strings.

  • void mapDefault(Action fun);
  • void mapDefault(Status delegate() d);
  • void mapDefault(Status function() f);

mapDefault maps the default action.

  • void mapMandatory(Action fun);
  • void mapMandatory(Status delegate() d);
  • void mapMandatory(Status function() f);

mapMandatory maps a mandatory action.

  • void mapAction(HTTPMethod method, string action, Action fun);
  • void mapAction(HTTPMethod method, string action, Status delegate() d);
  • void mapAction(HTTPMethod method, string action, Status function() f);

mapAction will map an action to a method and an action name.

Example implementation on a constructor

this(TView view) {
	super(view);

	mapDefault(&defaultAction);
	mapAction(HTTPMethod.GET, "GetData", &getData);
	mapAction(HTTPMethod.SAVE, "SaveData", &saveData);
}

After v0.4.0

this(TView view) {
    super(view,this);
}

4. Actions

In this case defaultAction will be used to tell the user he needs to specify an action, getData will get some json data and save data will save some json data.

5. defaultAction

Status defaultAction() {
	view.message = "You must specify an action.";

	return Status.success;
}

After v0.4.0

@HttpDefault Status defaultAction() {
    view.message = "You must specify an action.";

    return Status.success;
}

6. getData

Status getData() {
	auto id = to!int(view.params[0]); // The first parameter is the id

	auto data = Database.getData(id); // Gets data from the id
	
	return json(data); // Returns the data as a json response
}

After v0.4.0

@HttpAction(HTTPMethod.GET) Status getData() {
    auto id = to!int(view.params[0]); // The first parameter is the id

    auto data = Database.getData(id); // Gets data from the id

    return json(data); // Returns the data as a json response
}

getData can be called like /MyView/GetData/10000 where MyView is the view we call the action from, GetData is the route to the mapped action and 10000 is the first parameter specified.

7. saveData

Status saveData() {
	auto id = to!int(view.params[0]); // The first parameter is the id

	Database.saveData(id, view.request.json); // Saves the json data to the specified id.
	
	// Returns a json response with a boolean set as true for success
	return jsonString(q{{
		"success": true
	}});
}

After v0.4.0

@HttpAction(HTTPMethod.POST) Status saveData() {
    auto id = to!int(view.params[0]); // The first parameter is the id

    Database.saveData(id, view.request.json); // Saves the json data to the specified id.
		
    // Returns a json response with a boolean set as true for success
    return jsonString(q{{
        "success": true
    }});
} 

saveData can be called like /MyView/SaveData/10000 where MyView is the view we call the action from, SaveData is the route to the mapped action and 10000 is the first parameter specified. The body of the request should be json data to save.

For webservices you don't need to specify view to retrieve params, request, response etc.

Redirection

You can redirect to a specific url directly from a controller. However you must either return directly during the redirect call or manually return with Status.end afterwards. The redirect call already returns Staus.end to you.

Example:

Status someCall() {
    if (!isLoggedIn(view.request)) {
        return redirectTo("/login");
    }

    return Status.success;
}

That's about it, how to create a controller.