Chengyu Sun California State University, Los Angeles CS5220 Advanced Topics in Web Programming Develop Web Applications and Services Using Express Chengyu Sun California State University, Los Angeles
Using Express Application Generator Install global package express-generator express command options -h, --help -v, --view -c, --css --git
Template Engine A template engine combines templates with data to produce documents A.K.A. view engine, though it’s not just for views in MVC, e.g. email templates
JSP As A Template Engine <p>Hello, ${user.firstName}!</p> <c:if test=“${not empty tasks}”> <p>Your tasks for today:</p> <ul> <c:forEach items=“${tasks}” var=“task”> <li>${task}</li> </c:forEach> </ul> </c:if>
Basic Characteristics of a Template Engine Template language Access objects and properties Basic expression and control flow statements Server and/or client-side rendering Support for formatting and i18n Performance
Hogan <p>Hello, {{user.firstName}}!</p> {{#hasTasks}} <p>Your tasks for today:</p> <ul> {{#tasks}} <li>{{.}}</li> {{/tasks}} </ul> {{/hasTasks}} Developed by Twitter Use the “logic-less” Mustache template language
Handlebars <p>Hello, {{user.firstName}}!</p> {{#if tasks}} <p>Your tasks for today:</p> <ul> {{#each tasks}} <li>{{.}}</li> {{/each}} </ul> {{/if}} Extension to Mustache (arguably making it easier to use)
Dust Developed by LinkedIn <p>Hello, {user.firstName}!</p> {?tasks} <p>Your tasks for today:</p> <ul> {#tasks} <li>{.}</li> {/tasks} </ul> Developed by LinkedIn
EJS <p>Hello, <%= user.firstName %>!</p> <% if (tasks) { %> <p>Your tasks for today:</p> <ul> <% for( var i=0 ; i < tasks.length ; ++i ) { %> <li><%= tasks[i] %></li> <% } %> </ul> Syntax is similar to JSP scripting elements
Twig <p>Hello, {{user.firstName}}!</p> {% if tasks %} <p>Your tasks for today:</p> <ul> {% for task in tasks %} <li>{{task}}</li> {% endfor %} </ul> {% endif %} Originally a PHP template engine
Vash <p>Hello, @user.firstName!</p> if( tasks ){ <p>Your tasks for today:</p> <ul> @tasks.forEach( function(task) { <li>@task</li> } </ul> Use the Razor (i.e. the view engine in ASP.NET MVC) syntax
Jade / Pug p Hello, #{user.firstName}! if tasks p Your tasks for today: ul each task in tasks li= task Jade is renamed to Pug due to trademark problem
Build A MVC Web Application Understand the application structure created by Express Generator Data models and database access Controllers and views
Application Structure /public for static resources /routes for controllers /views for view templates /bin for executables package.json Packages npm start
Customize Configuration Using Environment Variables process.env.PORT || '3000' We often need to change runtime configuration such as port number, database url/username/password, log file location and so on Java applications usually use property files Node.js application prefer environment variables
Set Environment Variables Using dotenv Package Put the variables in a .env file, e.g. DBURL=mongodb://localhost/webtest USERNAME=cysun PASSWORD=abcd Run require('dotenv').config() at the beginning of the application Include and version control a .env.sample file
Model and DB Add Mongoose models Connect to database mongoose.connect(<DBURL>) Mongoose automatically creates a connection pool Disconnect during shutdown
Graceful Shutdown async function shutdown(callback) { await mongoose.disconnect(); if (callback) callback(); else process.exit(0); } process.on('SIGINT', shutdown); process.on('SIGTERM', shutdown); process.once('SIGUSR2', () => { shutdown(() => process.kill(process.pid, 'SIGUSR2')); }); Why didn’t we “await” on mongoose.connect()?
(model attributes in Spring) Controller router.get('/users', function(req, res, next) { User.find( (err, users) => { if(err) return next(err); res.render('users’, {title: 'Users', users: users}); }); Handle Error Render View View Name “Locals” (model attributes in Spring)
Handlebars Views layout.hbs is the default master page Set a layout local to use a different master page A child view is combined with the master page as {{{body}}} Triple braces mean do not escape content
Implement REST API Mostly it's just MVC without View Authentication and authorization with JWT Testing with Jasmine
Login Endpoint Use jsonwebtoken to create JWT jwt = require('jsonwebtoken'); jwt.sign( <payload>, <secret> [, options] ); Usually a User object Common claims such as sub and exp are in options
JWT Authorization Using Middleware Extract JWT token from Authorization header Verify the signature Attach the payload (i.e. the user object) to req and pass it onto the next middleware Return 401 if anything is wrong
Passport Passport is a popular Node.js authentication framework Different authentication schemes (called strategies) can be implemented on top of Passport
Using Passport-JWT … Example: passport-jwt.js Registers JWT strategy with Passport Extract JWT from Authorization header as a bearer token (other extractions also possible) Decode and verify token Passes decoded payload and a done() function to the callback function
… Using Passport-JWT … The callback function allows further processing of the payload, e.g. loading a full user object from database done(err, user) sets req.user which can be used by subsequent middleware
… Using Passport-JWT Add Passport to an Express application app.use( passport.initialize() ); app.use( '/api/', passport.authenticate('jwt', { session: false, failWithError: true }));
Jasmine Test Framework An all-in-one test framework for JavaScript Default test framework used by Angular
Using Jasmine npm install --save-dev jasmine ./node_modules/.bin/jasmine init Set jasmine as test script in package.json npm test
Test Example Test suite: describe Test spec: it beforeAll(), afterAll(), beforeEach(), afterEach() done() informs Jasmine that an asynchronous function has finished Test spec: it Expectations and matchers