synth icon indicating copy to clipboard operation
synth copied to clipboard

Set default resource

Open AdamQuadmon opened this issue 11 years ago • 4 comments

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();
});

AdamQuadmon avatar May 11 '14 06:05 AdamQuadmon

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!

JonAbrams avatar May 11 '14 07:05 JonAbrams

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?

AdamQuadmon avatar May 11 '14 07:05 AdamQuadmon

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');
});

JonAbrams avatar May 11 '14 07:05 JonAbrams

Cool... I'll try this one, thanks!

AdamQuadmon avatar May 11 '14 07:05 AdamQuadmon