View Source Routing

Each nova application have their own routes file. This file contains information about all the routes existing for this application.

Basic components

A simple route file could look something like this:

-module(my_app_router).

-export([routes/1]).

routes(_Environment) ->
  [#{prefix => "/admin",
    security => false,
    routes => [
      {"/", {my_controller, main}, #{methods => [get]}}
    ]
  }].

This will create a path for /admin which, when a user enters will call my_controller:main/1. The _Environment variable that is consumed by the routes function will have the value that nova:get_environment/0 returns. The environment variable is an important thing cause it enables the devlopers to define different routes for different environments. To change the running environment edit the sys.config file to include an {environment, Env} tuple under the nova application where Env can be any erlang-term.

The routing object

The routing object consists of three or four fields.

HTTP(S) Routing

{Route :: list(), {Controller :: atom(), Function :: atom()}, Options :: map()}

As you saw in the initial example in the Basic components section, we defined a route for the root path /.

Websocket routing

{Route :: list(), Controller :: atom(), Options :: map()}

Important

One needs to define protocol => ws in the options-map in order to enable websocket communications.

How to create routes

A route consists of four different components:

  • Path - This is the actual path to the endpoint. Eg "/admin"
  • Method - What method you want to support for this endpoint (get, post, update, delete). If you want to support all methods you can use the '_'-atom.
  • Controller - What erlang module should be called on when the path gets called.
  • Function - Which function in the Controller will be called when path gets called.

Using prefix

You can group paths where you prefix them with a path. This is especially useful when having several different nova applications running. A very common example would be if you had an administration interface. Then the prefix would be "/admin". Another example is versioned APIs.

Prefix is defined at top level of a route-entry which can be seen in the Basic components section of this chapter.

Secure routing

You can secure routes by providing a module and function to the security directive in the route entry. Here's a simple example of this:

#{prefix => "/admin",
  type => html,
  security => {security_controller, do_security},
  routes => [
    {"/", {my_controller, main}, #{methods => [get]}}
  ]
}

This will cause nova to call security_controller:do_security/1 before calling the actual controller for all routes defined in the above route entry. The security function should return a boolean (If the user can proceed or not).

An example of a security function:

do_security(Req) ->
    maps:get(host, Req) == "my_domain.com".

This will cause nova to return a 401 status code for all requests not coming from my_domain.com

Using plugins local to a set of endpoints

It's possible to configure a small set of endpoints with a specific plugin. This is done by adding a plugins key to the route entry. The value of this key should be a list of plugins to use for this route entry.

#{prefix => "/admin",
  plugins => [
    {pre_request, nova_json_schemas, #{render_errors => true}}
  ],
  routes => [
    {"/", {my_controller, main}, #{methods => [get]}}
  ]
}

In the example above we have enabled the pre-request-plugin nova_json_schemas for all routes under the /admin prefix. This will cause all requests to be validated against the JSON schema defined in the nova_json_schemas plugin. You can also include post-request-plugins in the same way.