Routing

Routing refers to how an application’s endpoints (URIs) respond to a client's request. The router is the main entry point for any horsepower application, without routes no server requests can be handled.

const { Router } = require('horsepower')

Router.get('/', client => client.response.html('Hello World'))

Routes

A route has 1-3 parameters for creating a route.

  • path – (optional) this is the path of the url which can be a string or regexp. For the url http://example.com/test/route the path would be /test/route. If not specified the path defaults to /.
  • options – (optional) this is the options for the route, such as middleware to be used.
  • controller (required) this is the callback/method to be executed. It can either be a string or a function.

Routes have multiple formats. One way is to use strings which then execute a controller module in the controllers directory.

// Calls the controller 'MyController' and executes the method 'main'
Router.get('/', 'MyController')

// Calls the controller 'MyController' and executes the method 'myMethod'
Router.get('/', 'MyController@myMethod')

// Calls the controller 'MyController' within the directory 'Public' and executes the method 'myMethod'
Router.get('/', 'Public/MyController@myMethod')

Another way to create a route is to pass a function as the last parameter.

Router.get('/', client => client.response.html('Hello World'))

Route Groups

A route group is a way to prefix paths and/or add middleware to a group of routes.

Router.group('/settings', () => {
  Router.get('/profile', 'Settings@profile')
  Router.get('/notifications', 'Settings@notifications')
})

In the above example two routes are created within a group. This will create two routes:

  • /settings/profile
  • /settings/notifications

This can be taken further by adding some middleware to the group. For example if we want to protect these routes to logged in users only, we could create an Auth middleware that checks your logged in status and applies it to the group as a whole instead of each route individually.

const { Auth } = require('../middleware/Auth.js')

Router.group('/settings', { middleware: [Auth] }, () => {
  Router.get('/profile', 'Settings@profile')
  Router.get('/notifications', 'Settings@notifications')
})

Route Domains

Router.domain() is not intended for mixing two or more unrelated websites together. Its main purpose is to separate routes into two or more domains/sub-domains that share content such as views, controllers, middleware, etc.

A route domain is a way to handle multiple domains/sub-domains that access the routes. For example example.com and api.example.com. The two routes both share the same configuration, database, sessions, etc. but you probably don't want them to share routes.

So, to separate the two we use Router.domain() which will add the routes to a particular domain.

Router.domain() calls should not be nested within other Router.domain() calls.

// These routes are only accessible from 'http://example.com'
Router.domain('example.com', () => {
  Router.get('/users', 'users@web')
})

// These routes are only accessible from 'http://api.example.com'
Router.domain('api.example.com', () => {
  Router.get('/users', 'users@api')
  Router.post('/login', 'users@login')
})

// This route is accessible from any domain
Router.get('/', 'welcome')

These two domains share a similar route /users, so the triggered route is dependent on the domain that called it.

api.example.com has an extra route /login, and if it is accessed from example.com a 404 will be returned.

There is also a route outside of the domain spec. These are routes that can be accessed by both example.com and api.example.com.

Route Resources

A route resource is a way to create a group of routes that all relate to one another. A resource takes two parameters each of which are strings.

  • name – This is the name of the resource, it is also part of the path
  • controller – This is the controller which is the name of the class with the actions predefined
Router.resource('photos', 'Photos')
MethodURIActionName
GET/photosmainphotos.main
GET/photos/createcreatephotos.create
POST/photosstorephotos.store
GET/photos/:idshowphotos.show
GET/photos/:id/editeditphotos.edit
PUT/photos/:idupdatephotos.update
DELETE/photos/:iddestroyphotos.destroy

Route methods

GET

Router.get('/', client => client.response.html('GET request to /'))

POST

Router.post('/', client => client.response.html('POST request to /'))

PUT

Router.put('/', client => client.response.html('PUT request to /'))

DELETE

Router.delete('/', client => client.response.html('DELETE request to /'))

PATCH

Router.patch('/', client => client.response.html('PATCH request to /'))

HEAD

Router.head('/', client => client.response.setHeader('Head-Request', 'to /'))

OPTIONS

Router.options('/', client => client.response.setHeader('Options-Request', 'to /'))

MATCH

The match route method allows for catching two or more specific types (GET, POST, etc.)

Router.match(['get', 'post'], '/', client => client.response.html('GET or POST request to /'))

ANY

The any route method allows for catching any type (GET, POST, etc.)

Router.any('/', client => client.response.html('any request to /'))