Deprecated

index.js in WebApps

index.js is the entry point and route configuration for a WebApp. The concept is influenced by Express.js. index.js is executed server side, which means Sitevision's Public API can be accessed, while browser objects cannot be accessed.

A simple index.js:

(function() {
   'use strict';

   var router = require('router');

   router.get('/', function(req, res) {
      res.render('/', {});
   });
}());

Routing

Routes handle how a WebApp responds to client requests. All WebApps have a unique segment in the URL where routing information is kept. WebApp routes differ from application routes since WebApp routes are local and should be used to keep state for a single WebApp. The router object provides methods to respond to the following request methods:

  • GET
  • PUT
  • POST
  • DELETE
  • PATCH (@since 2023.02.1)

A route definition has the following structure:

router.method(path, handler);

Basic examples:

var router = require('router'); // retrieve an instance of the router object

// respond to a GET-request to the root route ('/')
router.get('/', function(req, res) { 
   res.send('Hello from my WebApp!');
});

// respond to a GET-request to '/user'
router.get('/user', function(req, res){
   res.send('Hello from user route');
});

Middleware [@since 5.1]

A middleware function is a function that have access to the request object (req), response object (res) and a function (next) triggering the next function in the request-response chain. The next function will either be another middleware or the actual route function. Middleware functions are executed every time the app receives a request matching a route.

Middleware functions are registered using the router.use-method:

var router = require('router');

// register a middleware that will be executed every time the app recives a request
router.use((req, res, next) => { 
   if (req.method === 'PUT') {
      // do something
   }
	// trigger next function in the stack (next middleware or route function)   
   next(); 
});

router.get('/', (req, res) => {
   res.send('Hello');
});

Requests may be terminated and altered within a middleware. Keep in mind that the next()-function must be called in order to pass over control to the next function in the stack.

Multiple middleware functions may be registered and they will be executed in the order they are registered, i.e. top-down.

const router = require('router'),
   logUtil = require('LogUtil');

router.use((req, res, next) => { 
   logUtil.info('Hello from first');
   next(); 
});

router.use((req, res, next) => { 
   logUtil.info('Hello from second');
   next(); 
});

router.get('/', (req, res) => {
   logUtil.info('Hello from route');
   res.send('Hello');
});

// => 'Hello from first'
// => 'Hello from second'
// => 'Hello from route'

Route parameters

Route parameters are used to capture a value in the URL. Below is an example of a path that will capture id on the /user route.

// GET /user/123
router.get('/user/:id', function(req, res) {
 // route is matched and {id: 123} will be populated in the req.params object
});	

Router methods

router.getUrl(path [, queryStringParameters]) [@since 8.0]

Returns a URL given a path. Provide queryStringParameters as an object to include query string parameters. The URL will match configured paths in index.js.

router.getStandaloneUrl(path [, queryStringParameters]) [@since 8.0]

Returns a URL given a path. This type or URL is used to execute a route standalone, i.e. it will not be part of page rendering. This is very useful when you only want to target your route without any side effects. The SDK documentation contains example of client-side usage.

Request object (req)

The req object is a representation of the HTTP-request.

Properties

req.params

Object that contains parameters passed to a route. The object contains route parameters ('/user/:id'), query string parameters and values in the request body from POST, PUT and DELETE.

// GET /user/456
router.get('/user/:id', function(req, res) {
   logger.info(req.params.id); // 456
});

// GET /?foo=bar
router.get('/', function(req, res){
   logger.info(req.params.foo); // bar
});

// POST /addToBasket (productId=1)
router.post('/addToBasket', function(req, res){
   logger.info(req.params.productId); // 1
});	

req.cookies

Object that contains cookies from the request.

// Cookie basketId=789
router.get('/', function(req, res){
   logger.info(req.cookies.basketId); // 789
});	

req.xhr

Boolean indicating whether or not the request is an XHR (ajax) request.

router.get('/', function(req, res) {
   if (req.xhr) {
      return res.json({foo: 'bar'});
   }

   return res.render('/', {foo: 'bar'});
});	

req.session

Session data is stored and accessed through the req.session property. Session attributes are namespaced for WebApps/RESTapps, i.e. "global" session attributes cannot be accessed. Note that session data must be JSON serializable.

// WebApp/RESTApp x
router.get('/', function(req, res) {
   req.session.name = 'John Doe';
});
// WebApp/RESTApp y
router.get('/', function(req, res) {
   logger.info(req.session.name); // 'John Doe';
});

req.hostname [@since 4.5.3]

Hostname from the HTTP request.

router.post('/', function(req, res) {
   logger.info(req.hostname); //'developer.sitevision.se'
});

req.protocol [@since 5.0]

Protocol from the request (http or https).

router.get('/', (req, res) => {
   logger.info(req.protocol); //'https'
});

req.secure [@since 5.0]

Boolean shorthand checking req.protocol === 'https'.

router.get('/', (req, res) => {
   if (req.secure) {
      // ...
   }
});

If a load balancer or proxy is used, make sure that the client request protocol is forwarded to Sitevision.

req.method [@since 5.1]

HTTP method of the request.

router.use((req, res, next) => {
   if (req.method === 'PUT') {
      return res.status(403);
   }
   
   next();
});

req.path [@since 6.2]

Contains the path part of the request URL (the string used to resolve a route).

// example.com/appresource/4.x/12.x/users
router.get('/users', (req, res) => {
   logger.info(req.path); // '/users'
});

req.uri [@since 2023.04.1]

The client request uri (the uri that triggered rendering of this app). Note! The uri is not always equal to "the uri of current page".

// example.com/anything/something
router.get('/', (req, res) => {
   logger.info(req.uri); // '/anything/something'
});

req.serverside [@since 2023.08.1]

Whether the request is a server-side one or not. State is true when:

  • The WebApp is rendered via OutputUtil
  • The Sitevision indexing process renders the WebApp (Indexer user)
  • The Sitevision HTML extraction ("Web archiving") process renders the WebApp (typically the Extractor user)
router.get('/', (req, res) => {
   if (req.serverside) {
      // ...
   }
});

Methods

req.invalidateSession()

Invalidates current session.

req.updateSession() [@since 2023.03.1]

Re-synchronizes local req.session state with the global/shared App session state. Typically needed when multiple apps are executed intertwined

req.file(fileParamaterName) [@since 4.5.4]

Method to retrieve files from a multipart request. Files are exposed as sv:temporaryFile-nodes.

FileUtil and ImageUtil provide useful methods when working with temporary file nodes.

router.post('/upload', function(req, res) {
   var file = req.file('file');
      
   fileUtil.createFileFromTemporary(resourceLocatorUtil.getFileRepository(), file);
   res.render('/', {});
});

req.header(name) [@since 4.5.2]

Request headers from the HTTP-request

router.post('/', function(req, res) {
   logger.info(req.header('user-agent')); //mozilla....
});

Response object (res)

The res object is a representation of the HTTP-response.

Methods

res.set(name, value)

Sets a HTTP-header in the response. Returns this for chaining purposes.

res.set('Cache-Control', 'no-cache')
   .set('X-Content-Type-Options', 'nosniff');

res.type(type) [@since 4.5.2]

Sets the response Content-Type header. If type contains the “/” character, then it will be used as-is. Returns this for chaining purposes.

res.type('.html');      // => 'text/html'
res.type('html');       // => 'text/html'
res.type('text/html');  // => 'text/html'
res.type('svg');        // => 'image/svg+xml'
res.type('txt');        // => 'text/plain'

res.send(response)

Sends a character response. Type will be text/html if not explicitly set.

res.send('<p>Hello from WebApp!</p>');	
res.type('svg')
   .send('<svg version="1.1" ... </svg>');	

res.json(response)

Sends a application/json-response.

res.json({
   id: '123',
   foo: 'bar'
});	

res.sendFile(file)

Sends a file as response. Uses best effort for content type matching if no type is explicitly set. File argument must be a Sitevision JCR-Node of type sv:file, sv:image or sv:temporaryFile . Byte array (byte[]) is also valid as of Sitevision 5.0.1 (java.io.File is also allowed for legacy reasons).

res.sendFile(file);
res.type('application/xml; charset=ISO-8859-1')
   .sendFile(file);

Target your route with a standalone url when delivering files

res.status(code)

Sets the HTTP-status for the response. Returns this for chaining purposes.

res.status(404)
   .send('Not found');	

res.render(route, data)

Renders the WebApp. Rendering will always start from the main component. The route parameter will be passed to the data object, which will be the initial state for the WebApp's store.

router.get('/', function(req, res) {
   var data = {
      entries: [],
      buttonText: appData.get('buttonText')
   };
   
   res.render('/', data);
});

router.get('/search', function(req, res) {
   var data = {
      entries: [],
      buttonText: appData.get('buttonText')
   };
   
   res.render('/search', data);
});	

res.redirect(path [, queryStringObject] [, status]) [@since 4.5.3]
res.redirect(path [, status]) pre 4.5.3

Redirects to a path with a specified status. If a status is missing, it defaults to 302. A "back" redirection redirects the request back to the referer, defaulting to / when the Referer header is missing. A ".." redirection redirects to the relative path above current.

The queryStringObject argument will be converted and added as query string paramater.

Note! Redirecting does not work when the servlet response is committed, i.e. when rendering has started.

router.post('/addToBasket', function(req, res) {
   ...
   if (req.xhr) {
      return res.json(json);
   }
   // redirects back to referer
   return res.redirect('back'); 
});

router.post('/addToBasket', function(req, res) {
   // redirects to the URL derived from the /search path
   return res.redirect('/search'); 
});

router.post('/addToBasket', function(req, res) {
	// redirect with query string
   return res.redirect('back', {foo: 'bar'}); //url?foo=bar
});

Use a hook or target your route with a standalone url if you want to redirect

res.cookie(cookie)

Adds a cookie. The cookie parameter is an object that can have the following properties.

Note! Setting cookies does not work when the servlet response is committed, i.e. when rendering has started.

Property

Type

Description

Default

Since

name

String

The name of the cookie



value

String

The value of the cookie



httpOnly

Boolean

Flag to prevent client side scripts from accessing the cookie

false

5.0

secure

Boolean

Sets the cookie to be used with HTTPS only

false

5.0

maxAge

Number

The maximum age of the cookie in seconds.

  • A positive value indicates that the cookie will expire after that many seconds.
  • A negative value indicates a session cookie.
  • A zero value deletes the cookie.

-1

5.0

sameSite

String

Determines in what contexts this cookie will be available/sent. Valid values (case-insensitive) are:

  • "None"
  • "Lax"
  • "Strict"

Invalid values will be treated as "no value is set by the app" (i.e. no same site attribute will be added to the cookie)


7.1

res.cookie({
   name: 'basketId',
   value: '123',
   httpOnly: true,
   secure: true,
   maxAge: 3600,
   sameSite: 'Strict'
});

Use a hook or target your route with a standalone url if you want set cookies

res.clearCookie(name [, path])

Clears a cookie given a name. If path is missing, it defaults to '/'.

res.clearCookie('basketId');