Routing

Routing allows you to map URL templates to Controller actions

Create a new route

New routes can be added like this:

Router.add({
	name       : 'Blogpost#view',
	methods    : ['get', 'post'],
	paths      : '/{slug}',
	handler    : 'Blogpost#view'
});

The following properties are used:

  • name: The name of the route. In this case it uses the Class#method notation, but that's not strictly needed if a handler property is given
  • methods: An array of all supported methods
  • paths: The path(s) to match. This can also be an object, but not an array
  • handler: This should be a string of the Class#method notation. The Class should be the name of the controller, while the method should be the name of the action to execute. If no handler property is given, the value of the name property will be used.

Incoming request example

Say a request is made to /my-pretty-url, the following action would be called in the Blogpost controller:

Blogpost.setAction(async function view(conduit, slug) {
    var blogpost = await this.model.find('first', {conditions: {slug: slug}});
    
    if (!blogpost) {
        return conduit.notFound();
    }
    
    this.set('blogpost', blogpost);
    this.render('blogposts/view');
});

As you can see, the {slug} part of the URL is available as the second argument of the action.

The first thing we need to do in the action is get the actual post that matches that slug. It is possible that there is no blog post matching the slug, so then we have to return a 404. But we can change the URL so we get the blogpost document directly.

URL parameter type definitions

We can define the type of parameter we expect in the URL, here are some examples:

  • /{[Number]nr}/{name}: This route will only match if the first piece of the url is a valid number
  • /{[ObjectID]id}: This route will only match if the first piece of the url is a valid ObjectID
  • /{[Blogpost]slug}: This route will only match if a blogpost is found with the same slug

This allows us to rewrite our action like this:

Blogpost.setAction(async function view(conduit, blogpost) {
    this.set('blogpost', blogpost);
    this.render('blogposts/view');
});

We can also specify which document property should be compared against, in case the parameter name is different:

  • /{[Blogpost.slug]slug}: This is the same as the earlier route, just more verbose
  • /{[Project.slug]project_slug}/{[Blogpost.slug]blogpost_slug}: This fixes the problem of not being able to use 2 "slug" parameters in a single path

Shorthand

There is also a shorter way to add a new route. In this example, a GET route is added where the name and the handler property are the same.

Router.get('Blogpost#view', '/{slug}');