Skip to content
Tyler Swayne edited this page Feb 1, 2021 · 7 revisions

Having an entire applications routes organized in one place helps navigate and manage the rest of the codebase much more easily. The nexi router (by default located at src/routes.js) enables application routing, namespaces, and middleware in one place in a clean and organized fashion. With a simple syntax, the router provides rich routing functionality without clutter.

Contents

Basics

The routes.js file

The routes must be located at src/routes.js and must export a default function that looks like:

const router = (context, router) => {
  // Routes
}
module.exports = router

Basic routing

The router provides methods for routing using any http method. The basic structure of adding a route looks like: router.http_method('/my route', middleware, handler). Let's break that down a bit.

HTTP methods

As mentioned before, the router can route using any specific http method, or all.

  • GET request - router.get
  • POST request - router.post
  • PATCH request - router.patch
  • PUT request - router.put
  • DELETE request - router.delete
  • Any http method - router.any

Route paths

Nexi is built upon the express router, to learn about route parameters or advanced route strings using regex, check out the express route paths docs

Route handlers

Ultimately, the purpose of the router is to dispatch http requests to a controller action or a function "handler". The router makes this very simple.

Routing to a controller action router.get("/users", "userController#index") will route to the User controller's (src/controllers/user-controller.js) "index" method.

The name of the controller in the route must be a camel-cased representation of the controllers filename - example, routing to src/controllers/user-account-controller.js would look like "userAccountController#myAction".

To route to a controller in a nested directory, just include the path along with the controllers name - example, to route to src/controllers/api/user-controller.js just provide "api/userController#myAction".

Routing to a handler To route to function, simply provide the function as the last parameter to the route method:

const myCustomHandler = (req, res) => { res.send("Hello") }
router.get("/customRoute", myCustomHandler)

Route middleware

See the middleware section below to learn how to add middleware to an individual route or a group of routes.

Namespaces

The router provides a "namespace" method to easily group and define routes that contain the same prefix. The namespace method takes two arguments, 1) the segment to apply to all routes within the namespace, and 2) a function that is give a new router that is used to mount new routes to the namespace. That sounds a little complicated, but it's quite simple in practice - example:

const router = (context, router) => {
  router.get("/home", "homeController#show")
  router.namespace("/api", (apiRouter) => {
    apiRouter.get("/users", "api/userController#index")
  })
}
module.exports = router

In this example, everything defined in the namespace (using the apiRouter) will listen to routes prefixed with "/api". So here we have two routes - /home (defined outside the namespace), and /api/users.

Namespaces can also be nested within another namespace:

router.namespace("/api", (apiRouter) => {
  router.namespace("/v1", (apiRouter) => {
    apiRouter.get("/users", "api/v1/userController#index") // route to /api/v1/users
  })

  router.namespace("/v2", (apiRouter) => {
    apiRouter.get("/users", "api/v2/userController#index") /api/v2/users
  })
})

Middleware

Along with a simple interface, the router also provides an easy way to hook middleware into any route or group of routes.

The router can register middleware with a string camel-cased representation of its name (application middleware), or by using middleware by it's name (string) or by directly providing a function:

router.get("/", "homePageMiddleware", "homePageController#show")
router.get("/users", (req, res, next) => { next() }, "usersController#show")

View the middleware docs to learn about middleware and how to define application middleware that the router can use.

Route specific middleware One or many middelware can be passed to an indvidual route definition, in which that middleware will run in order before the handler is executed for that route only.

router.get("/", "homePageMiddleware", "anotherMiddlware", "homePageController#show")

Namespace middleware A namespace can be passed one or many middleware that it will apply in order to any route defined in that namespace:

router.namespace("/api", "apiMiddleware", (apiRouter) => {
  apiRouter.get("/users", "api/userController#index")
})

Miscellaneous middleware The router also provides a middleware method (router.middleware) that can register middleware for more flexible groups of routes.

At it's most basic usage router.middleware will apply to any route below it's definition:

router.get("/homepage", "homepageController#show") // This route will not run any application middleware

router.middleware("requireLogin") // This applies to all routes below this line

router.get("/secret", "secretsController#show")

You can also pass a path to router.middleware. This will apply middleware to any route below its definition that matches the path.

router.middleware("/api/*", "requireLogin") // This applies to all routes below this line that begin with "/api"

router.get("/homepage", "homepageController#show") // This route will not run any application middleware
router.get("/api/users", "usersController#show")

Lastly, you can define middleware blocks (similar to namespace blocks), that will only apply middleware to routes defined within the block. Middleware blocks do not accept a path (use a namespace for this use-case).

router.middleware("requireLogin", (requireLoginRouter) => {
  router.get("/secret", "secretsController#show")
})
router.get("/homepage", "homepageController#show") // This route will not run any application middleware
Clone this wiki locally