synth
synth copied to clipboard
Set default resource
I'm trying to have synth returning a default resource.
The following code in the back/back-app.js works, is there a better way to do it?
/**
* Array of available resources.
* Those resource names should not be used as url slugs for pages.
*
* @type {string[]}
*/
var availableResources = ['categories', 'pages'];
var defaultPage = 'home';
/**
* Return an array of path parts.
* It removes the first part of the array if it's empty.
*
* @param {string} path
* @returns {Array}
*/
var getPathTokens = function (path) {
/**
* Array of url path parts.
*
* For a path like `/` it returns an array
* of two empty strings.
*
* For a path like `/my-slug` it returns an array
* of two strings: ['', 'my-slug']
*
* @type {Array}
*/
var pathTokens = path.split('/');
if (pathTokens[0] === '') {
pathTokens = pathTokens.splice(1);
}
return pathTokens;
};
synth.app.use(function (req, res, next) {
var currentPathTokens = getPathTokens(req.originalUrl);
/**
* If `currentPathTokens` contains only one element
* and this element is not one of the available resources
* it assumes it's a page slug and change the route to point
* to `/page/slug-name`.
*
* If `currentPathTokens[0]` is empty it routes to the default one.
*/
if (currentPathTokens.length === 1
&& currentPathTokens[0].indexOf(availableResources) === -1) {
req.url = '/pages/' + (currentPathTokens[0] || defaultPage);
}
next();
});
That's very clever, you're rewriting the url path on the request. I had planned on adding the ability to define a particular resource as the base resource. This would allow you to reference a page with /page-id instead of /pages/page-id but I hadn't thought through yet on how to do it. I think I'll try out this technique, thanks!
As for whether the above code is good for defining a default result for a particular resource, I suppose if it works then it's great. I like how it's so well commented! An alternative would be to define a exports.getIndex method for the resource, and have it respond with the default response. To avoid duplicating code, you can have that method share a function with the exports.get method. For example:
function fetchPage (db, slug) {
return db.fetchOne({ slug: slug });
}
exports.getIndex = function (req, res) {
return fetchPage(req.db, 'home');
};
exports.get = function (req, res) {
return fetchPage(req.db, req.params.id);
};
I never thought of it before, but I suppose this could be a good feature to bake into Synth. If you don't need an index method for a resource, you can define a default id and call the exports.get method for that instead. Thanks for the suggestion!
What I don't like is the need to define the availableResources and listen on every requests.
If we can just intercept a 404 we can re-route the request to a default resource method. But I'm not a Express expert.
WDYT?
You could do the following:
...
module.exports = synth();
// Catch remaining unhandled requests
synth.app.get('/*', function (req, res) {
// Send back a 302 redirect
res.redirect('/pages/home');
});
Cool... I'll try this one, thanks!