# apostrophe-express
# Inherits from: apostrophe-module
This module initializes the Express framework, which Apostrophe
uses and extends to implement both API routes and page-serving routes.
The Express app object is made available as apos.app, and
the express object itself as apos.express. You can add
Express routes directly in your modules via apos.app.get,
apos.app.post, etc., however be sure to also check
out the route method available
in all modules for a cleaner way to implement API routes. Adding
routes directly to the Express app object is still sometimes useful when
the URLs will be public.
This module also adds a number of standard middleware functions and implements the server side of CSRF protection for Apostrophe.
# Options
# baseUrl (GLOBAL OPTION, NOT SET FOR THIS SPECIFIC MODULE)
As a convenience, req.absoluteUrl is set to the absolute URL of
the current request. If the baseUrl option at the top level,
not for this specific module is set to a string
such as http://mysite.com, or the APOS_BASE_URL environment variable is used to pass in the URL string, any site-wide prefix and req.url are
appended to that. Otherwise the absolute URL is constructed based
on the browser's request. Setting the baseUrl global option is
necessary for reasonable URLs when generating markup from a
command line task.
# address
Apostrophe listens for connections on all interfaces (0.0.0.0)
unless this option is set to another address.
In any case, if the ADDRESS environment variable is set, it is
used instead.
# port
Apostrophe listens for connections on port 3000 unless this
option is set to another port.
In any case, if the PORT environment variable is set, it is used
instead.
# bodyParser
The json and urlencoded properties of this object are merged
with Apostrophe's default options to be passed to the body-parser
npm module's json and urlencoded flavors of middleware.
# prefix (a global option, not a module option)
This module implements parts of the sitewide prefix option, which is a global
option to Apostrophe not specific to this module. If a prefix such
as /blog is present, the site responds with its home page
at /blog rather than /. All calls to res.redirect are adjusted
accordingly, and supporting code in other modules adjusts AJAX calls
made by jQuery as well, so that your code does not have to be
"prefix-aware" in order to work.
# afterListen (a global option, not a module option)
If Apostrophe was configured with an afterListen option, that
function is invoked after the site is ready to accept connections.
An error will be passed if appropriate.
# session
Properties of the session option are passed to the
express-session (opens new window) module.
If each is not otherwise specified, Apostrophe enables these defaults:
{
// Do not save sessions until something is stored in them.
// Greatly reduces aposSessions collection size
saveUninitialized: false,
// The mongo store uses TTL which means we do need
// to signify that the session is still alive when someone
// views a page, even if their session has not changed
resave: true,
// Always update the cookie, so that each successive
// access revives your login session timeout
rolling: true,
secret: 'you should have a secret',
cookie: {
path: '/',
httpOnly: true,
secure: false,
// Default login lifetime between requests is one day
maxAge: 86400000
},
store: (instance of connect-mongo/es5 provided by Apostrophe)
}
If you want to use another session store, you can pass an instance, but it's easier to let Apostrophe do the work of setting it up:
session: { store: { name: 'connect-redis', options: { // redis-specific options here } } }
Just be sure to install connect-redis, or the store of your choice,
as an npm dependency.
# csrf
By default, Apostrophe implements Angular-compatible CSRF protection (opens new window)
via an XSRF-TOKEN cookie. The apostrophe-assets module pushes
a call to the browser to set a jQuery ajaxPrefilter which
adds an X-XSRF-TOKEN header to all requests, which must
match the cookie. This is effective because code running from
other sites or iframes will not be able to read the cookie and
send the header.
All non-safe HTTP requests (not GET, HEAD, OPTIONS or TRACE)
automatically receive this proection via the csrf middleware, which
rejects requests in which the CSRF token does not match the header.
If the csrf option is set to false, CSRF protection is
disabled (NOT RECOMMENDED).
If the csrf option is set to an object, you can configure
individual exceptions:
csrf: {
exceptions: [ '/cheesy-post-route' ]
}
Exceptions may use minimatch wildcards (* and **). They can
also be regular expression objects.
You may need to use this feature when implementing POST form submissions that
do not use AJAX and thus don't send the header. We recommend using
$.post or $.jsonCall for your forms, which eliminates this issue.
There is also a minimumExceptions option, which defaults
to [ /login ]. The login form is the only non-AJAX form
that ships with Apostrophe. XSRF protection for login forms
is unnecessary because the password itself is unknown to the
third party site; it effectively serves as an XSRF token.
You can also pass options to the Express res.cookie (opens new window) call that sets the cookie:
csrf: {
exceptions: [ '/cheesy-post-route' ],
cookie: {
// Send it only if the request is HTTPS
secure: true
},
// Disable storing a true random CSRF token in sessions for all site visitors.
// Some protection is still provided via a well-known token and the Same Origin Policy.
// Logged-in users always get a true random CSRF token in their session.
// This setting is recommended because otherwise a session must be stored for
// 100% of site accesses.
disableAnonSession: true
}
Do not set the httpOnly flag as this will prevent legitimate same-origin
JavaScript from adding it to requests.
# trustProxy
Enables the "trust proxy" option for Express (opens new window).
Set to true to tell the Express app to respect X-Forwarded-* headers.
This is helpful when Apostrophe is generating http: URLs even though a
proxy like nginx is being used to serve it over https:.
# middleware
If a middleware array is present, those functions are added
as Express middleware by the requiredMiddleware method, immediately
after Apostrophe's standard middleware.
# Optional middleware: apos.middleware
This module adds a few useful but optional middleware functions
to the apos.middleware object for your use where appropriate:
# apos.middleware.files
This middleware function accepts file uploads and makes them
available via req.files. See the
connect-multiparty (opens new window) npm module.
This middleware is used by apostrophe-attachments.
# Module-specific middleware
In addition, this module will look for an expressMiddleware property
in EVERY module. If such a property is found, it will be invoked as
middleware on ALL routes, after the required middleware (such as the body parser) and
before the configured middleware. If the property is an array, all of the functions
in the array are invoked as middleware.
If expressMiddleware is a non-array object, it must have a middleware
property containing a function or an array of functions, and it may also have a
before property containing the name of another module. The function(s) in the
middleware property will be run before those for the named module.
If you need to run the middleware very early, the object may also have a
when property, which may be set to beforeRequired (the absolute
beginning, before even req.body is available), afterRequired (after all
middleware shipped with apostrophe-express but before all middleware passed
to it as options), or afterConfigured (the default, with other module
middleware).
# Methods
# createApp()
Create Apostrophe's apos.app and apos.express objects
# prefix()
Patch Express so that all calls to res.redirect honor
the global prefix option without the need to make each
call "prefix-aware"
# createData(req, res, next)
Standard middleware. Creates the req.data object, so that all
code wishing to eventually add properties to the data object
seen in Nunjucks templates may assume it already exists
# sessions()
Establish Express sessions. See options
# requiredMiddleware()
Install all standard middleware:
- Create the
req.dataobject on all requests - Implement Express sessions
- Add the cookie parser
- Angular-style CSRF protection
- Extended body parser (
req.bodysupports nested objects) - JSON body parser (useful with
$.jsonCall) - Flash messages (see connect-flash (opens new window))
- Internationalization (see apostrophe-i18n)
req.absoluteUrlalways available (also see baseUrl)
# useModuleMiddleware(when)
Implement middleware added via self.expressMiddleware properties in modules.
# configuredMiddleware()
# enableCsrf()
Enable CSRF protection middleware. See
compileCsrfExceptions for details on how to
exclude a route from this.
# compileCsrfExceptions()
Compile CSRF exceptions, which may be regular expression objects or
"minimatch" strings using the * and ** wildcards. They are
taken from options.csrf.exceptions. /login, /password-reset and /password-reset-request
are exceptions by default, which can be overridden via options.csrf.minimumExceptions.
Also invokes the csrfExceptions Apostrophe event, passing
the array of exceptions so it can be added to or otherwise modified
by modules such as apostrophe-headless.
# csrf(req, res, next)
Angular-compatible CSRF protection middleware. On safe requests (GET, HEAD, OPTIONS, TRACE),
set the XSRF-TOKEN cookie if missing. On unsafe requests (everything else),
make sure our jQuery ajaxPrefilter set the X-XSRF-TOKEN header to match the
cookie.
This works because if we're running via a script tag or iframe, we won't be able to read the cookie.
See the Angular docs for further discussion of this strategy. (opens new window)
# csrfWithoutExceptions(req, res, next)
See the csrf middleware method. This middleware method
performs the actual CSRF check, without checking for exceptions
first. It does check for and allow safe methods. This
method is useful when you have made your own determination
that this URL should be subject to CSRF.
# optionalMiddleware()
Establish optional middleware functions as properties
of the apos.middleware object. Currently just apos.middleware.files.
# addListenMethod()
Establish the apos.listen method, which Apostrophe will invoke
at the end of its initialization process.
# apostropheDestroy(callback)
Invoked by callAll when apos.destroy is called.
Destroys the HTTP server object, freeing the port.
# absoluteUrl(req, res, next)
Standard middleware. Sets the req.absoluteUrl property for all requests,
based on the baseUrl option or APOS_BASE_URL environment variable if available, otherwise based on the user's
request headers. The global prefix option and req.url are then appended.
req.baseUrl and req.baseUrlWithPrefix are also made available, and all three
properties are also added to req.data if not already present.
The baseUrl option should be configured at the top level or through the APOS_BASE_URL environment variable, for Apostrophe itself,
NOT specifically for this module, but for bc the latter is also accepted in this
one case. For a satisfyingly global result, set it at the top level instead.
# htmlPageId(req, res, next)
Makes the Apostrophe-Html-Page-Id header available
as req.htmlPageId. This header is passed by
all jQuery AJAX requests made by Apostrophe. It
contains a unique identifier just for the current
webpage in the browser; that is, navigating to a new
page always generates a new id, the same page in two tabs
will have different ids, etc. This makes it easy to
identify requests that come from the "same place"
for purposes of conflict resolution and locking.
(Note that conflicts can occur between two tabs
belonging to the same user, so a session ID is not enough.)
# addAbsoluteUrlsToReq(req)
Sets the req.absoluteUrl property for all requests,
based on the baseUrl option if available, otherwise based on the user's
request headers. The global prefix option and req.url are then appended.
req.baseUrl and req.baseUrlWithPrefix are also made available, and all three
properties are also added to req.data if not already present.
The baseUrl option should be configured at the top level, for Apostrophe itself or with the APOS_BASE_URL environment variable,
NOT specifically for this module, but for bc the latter is also accepted in this
one case. For a satisfyingly global result, set it at the top level instead.
If you want reasonable URLs in req objects used in tasks you must
set the baseUrl option or the APOS_BASE_URL environment variable for Apostrophe.
# afterInit()
Locate modules with middleware and add it to the list.
Also compile the CSRF exceptions, late, so that other
modules can respond to the csrfExceptions event.
# findModuleMiddleware()
Locate modules with middleware and add it to the list