SFRA Server-side Javascript - Source: modules/server/route.js menu

SFRA / Server-side JS / Source: modules/server/route.js

  1. 'use strict';
  2. var EventEmitter = require('./EventEmitter');
  3. /**
  4. * @param {Object} req - Request object
  5. * @returns {Object} object containing the querystring of the loaded page
  6. */
  7. function getPageMetadata(req) {
  8. var pageMetadata = {};
  9. var action = req.path.split('/');
  10. pageMetadata.action = action[action.length - 1];
  11. pageMetadata.queryString = req.querystring.toString();
  12. pageMetadata.locale = req.locale.id;
  13. return pageMetadata;
  14. }
  15. /**
  16. * @constructor
  17. * @param {string} name - Name of the route, corresponds to the second part of the URL
  18. * @param {Function[]} chain - List of functions to be executed
  19. * @param {Object} req - Request object
  20. * @param {Object} res - Response object
  21. */
  22. function Route(name, chain, req, res) {
  23. this.name = name;
  24. this.chain = chain;
  25. this.req = req;
  26. this.res = res;
  27. res.setViewData(getPageMetadata(req));
  28. EventEmitter.call(this);
  29. }
  30. Route.prototype = EventEmitter.prototype;
  31. /**
  32. * Create a single function that chains all of the calls together, one after another
  33. * @returns {Function} Function to be executed when URL is hit
  34. */
  35. Route.prototype.getRoute = function () {
  36. var me = this;
  37. return (function (err) {
  38. var i = 0;
  39. if (err && err.ErrorText) {
  40. var system = require('dw/system/System');
  41. var showError = system.getInstanceType() !== system.PRODUCTION_SYSTEM;
  42. me.req.error = {
  43. errorText: showError ? err.ErrorText : '',
  44. controllerName: showError ? err.ControllerName : '',
  45. startNodeName: showError ? err.CurrentStartNodeName || me.name : ''
  46. };
  47. }
  48. // freeze request object to avoid mutations
  49. Object.freeze(me.req);
  50. /**
  51. * Go to the next step in the chain or complete the chain after the last step
  52. * @param {Object} error - Error object from the prevous step
  53. * @returns {void}
  54. */
  55. function next(error) {
  56. if (error) {
  57. // process error here and output error template
  58. me.res.log(error);
  59. throw new Error(error.message, error.fileName, error.lineNumber);
  60. }
  61. if (me.res.redirectUrl) {
  62. // if there's a pending redirect, break the chain
  63. me.emit('route:Redirect', me.req, me.res);
  64. if (me.res.redirectStatus) {
  65. me.res.base.redirect(me.res.redirectUrl, me.res.redirectStatus);
  66. } else {
  67. me.res.base.redirect(me.res.redirectUrl);
  68. }
  69. return;
  70. }
  71. if (i < me.chain.length) {
  72. me.emit('route:Step', me.req, me.res);
  73. me.chain[i++].call(me, me.req, me.res, next);
  74. } else {
  75. me.done.call(me, me.req, me.res);
  76. }
  77. }
  78. i++;
  79. me.emit('route:Start', me.req, me.res);
  80. me.chain[0].call(me, me.req, me.res, next);
  81. });
  82. };
  83. /**
  84. * Append a middleware step into current chain
  85. *
  86. * @param {Function} step - New middleware step
  87. * @return {void}
  88. */
  89. Route.prototype.append = function append(step) {
  90. this.chain.push(step);
  91. };
  92. /**
  93. * Last step in the chain, this will render a template or output a json string
  94. * @param {Object} req - Request object
  95. * @param {Object} res - Response object
  96. * @returns {void}
  97. */
  98. Route.prototype.done = function done(req, res) {
  99. this.emit('route:BeforeComplete', req, res);
  100. this.emit('route:Complete', req, res);
  101. };
  102. module.exports = Route;