Title: Express routing composition made clean.
Use Case:
- We have two resources, resource Businesses(B) and resource Addresses(A).
- We want (B)’s and (A)’s routing to be in seperate files.
- We want to easily compose (A) and (B) by mounting (A) as a subresource to (B).
Solution:
function mountRouteModules(expressRouter) {
return function mount({
resources = [],
resourceMountPath = '/',
parentRouteModule = expressRouter
}) {
resources.forEach(resource => {
const {
resourceModule = () => expressRouter,
subResourceMountPath = '/',
resourceDependencies = [],
subResources = []
} = resource
if (typeof resourceModule !== 'function') {
throw new Error('Expected resourceModule to be a function.')
}
const routeModule =
resourceModule(...Object.values(resourceDependencies))
if (!!subResources.length) {
mount({
resources: subResources,
resourceMountPath: subResourceMountPath,
parentRouteModule: routeModule
})
}
parentRouteModule.use(resourceMountPath, routeModule)
})
}
Before solution:
-- addressRoutes.js
const router = express.Router({ mergeParams: true })
module.exports = {
router.route('/addresses').get((req, res) => {
return addressController.getAddress(req)
})
return router
}
-- businessRoutes.js
const addressRoutes = require('somePath.../addressRoutes.js')
const router = express.Router()
router.use('/businesses/:business_id', addressRoutes)
module.exports = {
router.route('/businesses').get((req, res) => {
return businessController.getBusiness(req)
})
return router
}
After solution:
-- addressRoutes.js
const router = express.Router({ mergeParams: true })
module.exports = {
router.route('/addresses').get((req, res) => {
return addressController.getAddress(req)
})
return router
}
-- businessRoutes.js
const router = express.Router()
module.exports = {
router.route('/businesses').get((req, res) => {
return businessController.getBusiness(req)
})
return router
}
-- routes.js
const mountRouteModules = require('mount-route-modules')
const businessRoutes = require('somePath.../businessRoutes.js')
const addressRoutes = require('somePath.../addressRoutes.js')
const app = express()
const resources = [
{
resourceName: 'businesses', // Solely for readability
resourceModule: businessRoutes,
subResourceMountPath: '/businesses/:business_id',
resourceDependencies: [],
subResources: [
{
resourceName: 'addresses', // Solely for readability
resourceModule: addressRoutes,
resourceDependencies: []
}
]
}
]
module.exports = mountRouteModules(app)({ resources })