An SFRA route is a name, a chain of middleware and a template, joined at run time by server.js. Intellij SFCC joins them in the editor: req and res are typed in every callback, middleware opens in SFRA's modules, an append finds the route it extends, and the template a route renders gets its model as pdict
req and res complete with their types, so req.currentCustomer.profile and res.render come up as you type. Cmd+Click on server.middleware.https opens the function in your project's modules/server/middleware.jsBefore you start
| Needs | Why |
|---|---|
SFRA's modules folder marked as Modules (Global Modules) Root | require('server') loads it, see B2C modules and global modules |
| A valid license or trial | Route and template completion, navigation, gutter icons and Code Vision are paid features, see Purchase & License |
Typed req and res
Every function passed to server.get, server.post, server.use, server.append, server.prepend and server.replace gets SFRA's types, with no JSDoc:
| Parameter | Type | Members you use most |
|---|---|---|
req | sfra.Request | querystring, httpParameterMap, form, currentCustomer with profile, addressBook, wallet and raw, locale, session, geolocation, pageMetaData |
res | sfra.Response | render, json, setViewData, getViewData, redirect, setStatusCode, cacheExpiration, setHttpHeader, print |
next | sfra.Next | Call it to run the next step |
server.get('Show', server.middleware.https, function (req, res, next) {
var profile = req.currentCustomer.profile; // sfra.Profile
this.on('route:BeforeComplete', function (req, res) {
res.setViewData({ updated: true }); // typed here too
});
res.render('account/loyalty', { points: loyaltyHelpers.getPoints(profile.customerNo) });
next();
});Inside a route function, this.on takes the route events route:Start, route:Redirect, route:Step, route:BeforeComplete and route:Complete, and types the req and res of its callback
server and middleware
| Code | Cmd+Click opens | Completes |
|---|---|---|
require('server') | SFRA's modules/server.js | |
server.get, server.post, server.use, server.replace | The method in modules/server/server.js | get, post, use, replace, middleware, forms, querystring and the other members your SFRA copy defines |
server.middleware.https | The https function in modules/server/middleware.js | https, http, get, post, include and any middleware your copy adds |
server.forms, server.querystring | The assignment in modules/server.js |
Members your SFRA copy doesn't define, such as server.getRoute, open the bundled typings. Middleware of your own cartridges, such as csrfProtection.generateToken or userLoggedIn.validateLoggedIn, comes in through require like any module, see Module Resolution
Extend a route
server.extend(module.superModule) makes a controller an override of the same controller further right on the cartridge path. Then:
| Code | What happens |
|---|---|
server.append(''), server.prepend(''), server.replace('') | Completes the routes of the controller you extend, each with its cartridge |
Cmd+Click on 'Show' in an append or prepend | Opens the route it extends, in the nearest cartridge further right on the site's cartridge path |
Cmd+Click on 'Show' in server.get('Show', ...) | Lists every other definition, append, prepend and replace of the route |
| The lenses above a route | append (1), prepend (2) or replace (1) list the cartridges that extend it, see SFRA extensions |
To find a route from anywhere, use the B2C Entry Points tab of Search Everywhere. For URLUtils.url('Cart-Show') and other route strings, see Routes and controllers
View data in templates
res.setViewData({ loyaltyPoints: points }) in an append adds pdict.loyaltyPoints to the template the base route renders, in its own cartridge or any other. So does viewData.loyaltyPoints = points on the object res.getViewData() returns. The plugin reads both across the route's handlers, every server.append and server.prepend of it and its middleware, up to 50 functions deep, so csrfProtection.generateToken adds pdict.csrf
In the template, pdict. completes the member with its type, and quick documentation (F1, Ctrl+Q) names the line that sets it. A middleware or helper the plugin can't follow, such as decorate(req, res), keeps the members it knows and stops the unknown member warning, see Render calls
Picked templates
A route that picks its template at run time keeps every link of a literal path:
var template = req.querystring.panel ? 'account/dashboardPanel' : 'account/accountDashboard';
res.render(template, { account: accountHelpers.getAccountModel(req) });| Form | Example |
|---|---|
A variable, also one set in if and else | var view = 'a/mobile', then res.render(view, model) |
?: | res.render(isGuest ? 'checkout/guest' : 'checkout/login', model) |
|| and ?? | res.render(req.querystring.view || 'search/searchResults', model) |
Each path completes template paths, gets the Navigate to template gutter icon , opens with Cmd+Click and is found and renamed with its template. The model joins the pdict of each template. With copies in several cartridges the icon reads Navigate to template (2 cartridges) and opens Choose Template, in the order the server tries them, see Gutter icons
A path built from parts, such as 'account/' + name, or passed in as a function parameter, isn't followed
Troubleshooting
| Symptom | What to do |
|---|---|
req. or res. lists nothing in a route | Mark SFRA's modules folder as Modules (Global Modules) Root and check the license, see Before you start |
server.append('') lists nothing | Add server.extend(module.superModule) and check that another linked cartridge has a controller with the same name |
| An append opens no base route | The base controller is in a cartridge that isn't linked, or has another file name |
A pdict member from an append is missing in the template | Set it with res.setViewData({...}) or on the object res.getViewData() returns, in the route's own handler, an append or a middleware |
| A picked template has no gutter icon | The path is built from parts or passed in, see Picked templates |