Suppose I want to have REST endpoints which look roughly like this:
/projects/
/projects/project_id
/projects/project_id/items/
/projects/project_id/items/item
What you're looking for is something similar to Express's Router. In fact, Express does a good job of burying the usefulness of this feature so I'll re-post an example here:
// routes/users.js:
// Note we are not specifying the '/users' portion of the path here...
const router = express.Router();
// index route
router.get('/', (req, res) => {... });
// item route
router.get('/:id', (req, res) => { ... });
// create route
router.post('/', (req,res) => { ... });
// update route
router.put('/:id', (req,res) => { ... });
// Note also you should be using router.param to consolidate lookup logic:
router.param('id', (req, res, next) => {
const id = req.params.id;
User.findById(id).then( user => {
if ( ! user ) return next(Boom.notFound(`User [${id}] does not exist`));
req.user = user;
next();
}).catch(next);
});
module.exports = router;
Then in your app.js or main routes/index.js where you assemble your routes:
const userRoutes = require('./routes/users')
// now we say to mount those routes at /users! Yay DRY!
server.use('/users', userRoutes)
I'm actually disappointed to find this SO post with no other responses so I'll assume there's nothing out of the box (or even a third-party module!) to achieve this. I imagine it might not be too difficult to create a simple module that uses functional composition to remove duplication. Since each of those hapi route defs is just an object it seems like you could make a similar wrapper like the following (untested):
function mountRoutes(pathPrefix, server, routes) {
// for the sake of argument assume routes is an array and each item is
// what you'd normally pass to hapi's `server.route
routes.forEach( route => {
const path = `${pathPrefix}{route.path}`;
server.route(Object.assign(routes, {path}));
});
}
EDIT In your case since you have multiple layers of nesting, a feature similar to Express's router.param would also be extremely helpful. I am not terribly familiar with hapi so I don't know if it already has this capability.
EDIT #2 To more directly answer the original question, here is a hapi-route-builder has a setRootPath()
method that lets you achieve something very similar by letting you specify the base portion of the path once.