Installation
INFO: Currently routing with hadron works only with the Express framework.
npm install @brainhubeu/hadron-express --save
Express integration
We need to include hadron-express
package while initializing hadron.
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.PORT || 8080;
const expressApp = express();
expressApp.use(bodyParser.json());
hadron(expressApp, [require('../hadron-express')], config).then((container) => {
expressApp.listen(port);
});
Basic routing setup
To set up routes with Hadron, we are able to include them as objects in config object under key routes
.
const config = {
routes: {
helloWorldRoute: {
callback: () ='Hello world !',
methods: ['GET'],
path: '/',
},
},
};
Basic, required structure of route config object includes:
-
callback
- function called when request is made, returned value will be send as a response (except if you callres
methods directly) -
methods
- array of HTTP methods -
path
- route path
Callback
The callback function can take route parameters as an arguments. Hadron also allows us to grab a container value easily.
routeWithParam: {
callback: (firstParam) => `firstParam value: ${firstParam}`,
methods: ['GET'],
path: '/:firstParam',
}
Using this simple example, if we send a request, for example http://localhost/foobar
will provide a response as below:
"firstParam value: foobar"
When you would like to implement multiple route parameters, their order as arguments in callback does not matter, argument name needs only to match parameter name.
multipleParams: {
callback: (secondParam, firstParam) =`${firstParam} ${secondParam}`,
methods: ['GET'],
path: '/:firstParam/:secondParam',
}
GET request with path: http://localhost/Hello/World
will result with following response:
"Hello World"
Locals (available from 2.0.0)
As a third parameter, hadron delivers locals
from your response. You can inject its content in middlewares, e.g.
const route = {
callback: (req, container, locals) => locals.testValue,
middlewares: [
(req, res, next) => {
res.locals.testValue = 'I am test!';
next();
},
],
};
Retrieving items from container in callback
Callback function provides a simple way to retrieve items from container with ease. Simply set item's key as callback function's argument. Let's see an example below:
hadron(expressApp, [require('../hadron-express')], {
routes: {
routeWithContainerValue: {
// sayHello argument will refer to container value
callback: (sayHello = `hadron says: ${sayHello}`),
methods: ['GET'],
path: '/',
},
},
}).then((container) => {
// Register value under key sayHello
container.register('sayHello', 'Hello World');
});
After sending a request to the /
path, the response will look like that:
"hadron says: Hello World"
Hadron will first look for request parameters and next if not found any, it will look for value in the container. So if you register a key foo
in a container and set the route param under the same name, it will inject param's value into callback's argument foo.
container.register('foo', 'container');
exampleRoute: {
callback: (foo) =`foo value: ${foo}`,
methods: ['GET'],
path: '/:foo',
},
Response for GET
request /param will look like this:
"foo value: param"
Middlewares
Note: Currently middlewares only refer to express.
Routing with Hadron provides a middleware support. You need to pass array with middleware functions to a middleware
key in route config.
For example:
middlewareExample: {
callback: () => {
console.log('Callback function');
},
methods: ['GET'],
middleware: [
(req, res, next) => {
console.log(`First middleware`);
next();
},
(req, res, next) => {
console.log(`Second middleware`);
next();
},
],
path: '/',
},
GET
request to /
will log to the console following:
First middleware
Second middleware
Callback function
Middlewares take three arguments: request
, response
and next
. First two are objects and third one - function which executed continues request flow.
You can read more about middlewares in express guide
Routes nesting (available from 2.0.0)
In case of more complicated routing, hadron-express offers possibility to nest routes. That way, You can specify bunch of route properties, that all child routes will inherit.
Route properties that can be inherited:
- path (will add parent's path beforehand new path),
- middlewares
- methods,
const nestedRoute = {
middleware: [myTestMiddleware],
method: ['GET'],
path: '/test',
routes: {
route1: {
// path here is going to be /test/test1/, it's going to have 'GET' method on default and middleware myTestMiddleware will be called before
path: '/test1',
callback: () => 'It works! Trust me...',
},
route1: {
// path here is going to be /test/test2/, it's going to have 'GET' and 'POST' methods on default and middlewares myCustomMiddleware and myTestMiddleware will be called before
path: '/test2',
method: ['POST'],
middleware: [myCustomMiddleware],
callback: () => 'It works! Trust me...',
},
},
};
If You would like to override parent property, just define new one with $
sign before, e.g. $middlewares
, $path
, $method
.
const nestedRoute = {
middleware: [myTestMiddleware],
method: ['GET'],
path: '/test',
routes: {
route1: {
// path here is going to be /test1/, it's going to have 'GET' method on default and middleware myTestMiddleware will be called before
$path: '/test1',
callback: () => 'It works! Trust me...',
},
route1: {
// path here is going to be /test/test2/, it's going to have 'GET' and 'POST' methods on default and no middlewares
path: '/test2',
method: ['POST'],
$middleware: [],
callback: () => 'It works! Trust me...',
},
},
};
You can define nested route endlessly, all of them will inherit properties of it's parent and other ancestors (of course if they were not overwritten with $
sign).
const nestedRoute = {
middleware: [myTestMiddleware],
method: ['GET'],
path: '/test',
routes: {
route1: {
// path here is going to be /test/test2/, it's going to have 'GET' and 'POST' methods on default and no middlewares
path: '/test2',
method: ['POST'],
$middleware: [],
callback: () => 'It works! Trust me...',
routes: {
// path here is going to be /test/test2/deep/, it's going to have 'GET' and 'POST' methods on default and no middlewares
deepRoute1: {
path: 'deep',
callback: () => 'The Dwarves delved too greedily and too deep',
},
},
},
},
};