# Routers

## Defining a Router

Routers are the main entry point to a Blueprint application. The router consists of paths (*i.e.*, relative urls) that clients uses to make request against the application. The paths are then bound to controller actions to create *routes*. Routers are essential application entities. All routers are defined in `app/routers`.&#x20;

You define a router by extending the `Router` class with a router specification, and exporting the extended class from its router module. Below is an example router named `message` with an empty specification.

{% code title="app/routers/message.js" %}

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    // TODO router specification goes here
  }
});
```

{% endcode %}

## Router Paths

The paths of a router are the relative urls that provide an entry point to the application. If you think of an application as a building, then the paths represent the entryways for the building. Each entryway is in a different location and provides access to a different part of the building.

Paths are defined as keys on the `specification` property of the router, and begin with a forward slash (`/`). The example below updates our `message` router with the single path `/messages`.

{% code title="app/routers/message.js" %}

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
    
    }
  }
});
```

{% endcode %}

Now, we have an entryway into our application. We, however, do not know what action we need to perform when a clients wants to use this path.

## Reactions to Paths

If you are familiar with HTTP requests, each path in the request requires a [HTTP verb](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods), such as `GET`, `POST`, `PUT`,  and `DELETE`. The verb notifies the server (*i.e.*, the application in our case) of what action to execute when a client sends a request to the corresponding path. In our current specification, we have defined a path, but we have not defined what HTTP verb on the path is active, and what action the HTTP verb executes. We call this a *reaction*.

{% hint style="info" %}
A *reaction* is when you define the HTTP verb, and the action its causes.
{% endhint %}

Let's update our `message` router to support creating messages.

{% code title="app/routers/message.js" %}

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      post: { action: 'message@create' }
    }
  }
});
```

{% endcode %}

Now, our message router has defined its first route `POST /messages`. When a client sends this HTTP request to the application, it will execute the `create` action on the message `controller`. We will visit how to implement this action later in the guide. For now, let's focus on the route definition in the `message` router.

As shown in the `message` router, the key for nested objects of a path is a HTTP verb. In this example, the HTTP verb is `post`.&#x20;

{% hint style="info" %}
A Blueprint router supports the HTTP verbs defined in the [jshttp](https://github.com/jshttp/methods) module.
{% endhint %}

### Actions

The value (or reaction) of the HTTP verb in the router definition can be a controller action. This is signified by the `action` property in the hash associated with the corresponding HTTP verb. In our example above, the controller action is `message@create`. This means that `POST /messages` is going to invoke the `create` action on the `message` controller.

There is no one-to-one mapping of paths to controller actions. For example, it is possible to have different paths from the same router, or a different router, bind to the same controller action. This reason for doing so is because either path may have different [policies](https://blueprint.onehilltech.com/developer-guide/policies) for invoking the action.

#### Binding to default actions

Some controller may have a single default action named `__invoke()`. When binding a path to the default action of a controller, you do not need to provide the action name. Instead, just specify the controller name in the `action` property. The following example illustrates binding the path to the default action for the `message` controller.

{% code title="app/routers/message.js" %}

```javascript
const 
{ Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      post: { action: 'message' }    // bind to default action in message controller
    }
  }
});
```

{% endcode %}

### Static Views

A [view](https://blueprint.onehilltech.com/developer-guide/application-resources/static-views) is a document that captures a reusable representation of a response to a request that can be rendered on demand.  An example of a view is an HTML document. Similar to actions, you can specify that a path is bound to a static view. Just use the `view` property instead of the `action` property for the corresponding route.

{% code title="app/routers/message.js" %}

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      get: { view: 'messages' }
    }
  }
});
```

{% endcode %}

Now, the `GET /messages` route will use the `messages` view to display the messages to the users.

## Dynamic Routes

Up until this point, we have been defining static routes. A *static route* is a route that has a path with no variable parts. A *dynamic route* therefore is a route that has variable parts. For example, `/messages` is a static route. But, `/messages/1` and `messages/2` are dynamic routes. This is because the part of the path after `/messages` is can change depending what context the client is hoping to access.

We define dynamic routes by including a parameter in the path. A parameter begins with a colon (`:`). For example, `:messageId` is a parameter.

Let's define a route for getting a single message:

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      get: { view: 'message' }
      
      '/:messageId': {
         get { action: 'messages@getOne'}
      }   
    }
  }
});
```

In the example above, `/messages/:messageId` is dynamic route. Likewise, the `:messageId` parameter will be accessible on  `req.params` as `req.params.messageId`.

## Nested Routes

You may have noticed that when we defined the [dynamic route for getting a single message](#dynamic-routes), we created a route under `/messages`. This is call a *nested routed*. Nested routes is Blueprint's method for allowing you to extend an existing route with a child route, and reduce problems related to defining related routes. The dynamic route from above is the same as this one.

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      get: { view: 'message' }
    },
    '/messages/:messageId': {
      get { action: 'messages@getOne'}
    }   
  }
});
```

The main difference between the definition above, and the following one:

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/messages': {
      get: { view: 'message' }
      
      '/:messageId': {
         get { action: 'messages@getOne'}
      }   
    }
  }
});
```

is we are inheriting the `/messages` definition. This means that allow properties, such as [policies](https://blueprint.onehilltech.com/developer-guide/policies) and [Express middleware](#using-middleware), of the `/messages` route will also apply to the `/messages/:messageId` route.

### Using Directories

As your Blueprint application grows, you will find that defining all your routes in a single router will not scale to your needs. This will even be the case with nested routes in single router. To assist with this problem, Blueprint allows you to use directories to define nested routes.&#x20;

For example, let's assume you are working on v1 of your Blueprint application, and the application has 3 different routers. As part of your design, you want all routes to have a `/v1` prefix. The simple approach is to just nest all paths in a router under `/v1`. This suffices, but it also means you have to do the same for each routers. Likewise, changing the name of the prefix means you have to update each router definition.&#x20;

An easier, and better, solution would be to not nest all the paths in each router under `/v1`, but place all routers under the `v1/` directory. For example:

```bash
app/routers
  - v1/
    - message.js
    - comment.js
    - like.js
```

Now, all routes in the `message`, `comment`, and `like` router will be prefixed with `/v1`. For example, `/v1/messages` and `/v1/messages/:messageId` are valid routes.

{% hint style="info" %}
Using directories for nested routes is a easy way to implement versioned routes (*e.g.*, `/v1` vs `/v2`).
{% endhint %}

## Middleware

[Express middleware](https://expressjs.com/en/guide/using-middleware.html) are methods that provide domain-specific functionality to an Express application. For example, you have middleware the logs all the requests to a database, or middleware the authenticates access to a given route. Since Blueprint is a framework built atop [Express](https://expressjs.com/), it is possible to use Express middleware in a Blueprint application.&#x20;

{% hint style="info" %}
Blueprint has built-in middleware for logging, parsing requests, cookies, and validating request input because their load order is important.
{% endhint %}

You use the `use` keyword to add middleware to a route. For example, here we are adding the [CORS middleware](https://github.com/expressjs/cors) to our route.

```javascript
const { Router } = require ('@onehilltech/blueprint');
const cors = require ('cors');

module.exports = Router.extend ({
  specification: {
    '/': {
      use: cors ()        // apply CORS middleware to route
    },
    
    '/messages': {
      get: { view: 'message' }
      
      '/:messageId': {
         get { action: 'messages@getOne'}
      }   
    }
  }
});
```

The `use` property takes an Express middleware function with the signature `function (req, res, next)`, or an array of Express middleware functions.

## Mounting External Routers

One feature you will learn when working with [Blueprint modules](https://blueprint.onehilltech.com/developer-guide/untitled-1) is you can define routers inside a module for reuse across different applications. The benefit of this feature is the [Blueprint module](https://blueprint.onehilltech.com/developer-guide/untitled-1) can provide a public access point for how the module can be used by a client. Routers defined in a Blueprint module, however, are not loaded by default. We do this because we want to allow developers to control what routers (and paths) are exposed by the containing application.

This means that developers need a method for defining what routers (and paths) from a [Blueprint module](https://blueprint.onehilltech.com/developer-guide/untitled-1) are available via the application. We call this process *mounting*.&#x20;

To mount a router, you define the path and use the `mount()` method. Here is an example of mounting a router to the `/images` path.

```javascript
const blueprint = require ('@onehilltech/blueprint');

module.exports = {
  '/images': blueprint.mount ('blueprint-images-cdn:images')
}

```

The example above will mount the `images` router from the `blueprint-images-cdn` [Blueprint module](https://blueprint.onehilltech.com/developer-guide/untitled-1). If you do not provide a module name (*i.e.*, only use `images`), then the router is assumed to be part of the application.
