Horváth, Győző
senior lecturer
horvath.gyozo@inf.elte.hu
Financed from the financial support ELTE won from the Higher Education Restructuring Fund of the Hungarian Government
node
command (interactive shell)node filename
(executing a file)npm
commandnode_modules
directorynpm init
: creating a project description file (package.json
)npm install package
: installing package locallynpm install -g package
: installing package for global accessnpm install package --save
: installing and saving a package as a dependency to package.json
npm install package --save-dev
: installing and saving a package as a development dependency (e.g. test runner)require
: imports a modulemodule.exports
: exports functionality//Modul: math.js
function add(a, b) {
return a + b;
}
module.exports = add;
//Main program: index.js
var add = require('./math');
console.log(add(2, 3));
// math.js
module.exports = {
add: function (a, b) { return a + b; },
multiply: function (a, b) { return a * b; },
};
// index.js
var math = require('./math');
console.log(math.add(2, 3));
// OR
var multiply = require('./math').multiply;
console.log(multiply(2, 3));
var http = require('http');
var port = process.env.PORT || 3000;
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello browser!\n');
}).listen(port);
var express = require('express');
var app = express();
var port = process.env.PORT || 3000;
app.listen(port);
var express = require('express');
var app = express();
var port = process.env.PORT || 3000;
var server = app.listen(port, function () {
console.log('Server is running!');
});
var express = require('express');
var http = require('http');
var app = express();
var port = process.env.PORT || 3000;
http.createServer(app).listen(port);
request
object
response
object
Middleware is a function, which has access to the
request
)response
)next
)function (request, response, next) {
}
function (request, response, next) {
//arbitrary code
//reading/writing the request, response object
next();
}
//General form
app.use([path], middleware [, middleware]);
//Hit by any route
app.use(function (req, res, next) {
console.log('Middleware');
next();
});
//Run on every route starting with '/users'
app.use('/users', function (req, res, next) { /*...*/ });
//Example endpoint
app.use(function (req, res, next) {
console.log('Endpoint');
});
The express application is a series of middlewares ending with an endpoint:
middleware
middleware-->middleware
middleware
middleware
middleware-->endpoint
Assigning an URI endpoint to a route handler (controller).
URIs with endpoints:
http://expressjs.com/guide/routing.html
http://localhost:8080/snippets/3
path
)METHOD
)handler
)//Generally
app.METHOD(path, handler [, handler ...]);
app.METHOD(path [, middleware, ...] handler);
//For example
app.get('/apple', function (req, res) {
//code
});
get
post
put
delete
options
all
//szöveg
app.get('/apple', function (req, res) { /* ... */ });
app.get('/public/index.html', function (req, res) { /* ... */ });
//szövegminta
app.get('/ab?cd', ...); //acd or abcd
app.get('/ab+cd', ...); //abcd, abbcd, abbbcd, ...
app.get('/ab*cd', ...); //abcd, ab1cd, abSOMETHINGcd
app.get('/ab(cd)?e', ...); //abe, abcde
//reguláris kifejezés
app.get(/apple/, ...); //apple
app.get(/.*apple$/, ...); //apple, chapple, redapple
next()
(endpoint)app.get('/', function (req, res) { /*...*/ });
app.get('/', function (req, res, next) {
console.log('middleware');
next();
}, function (req, res) {
console.log('end');
})
app.get('/', middleware1, middleware2, middleware3);
app.get('/', [middleware1, middleware2, middleware3]);
//Application-level
app.use(...);
//Router-level
var router = express.Router();
router.use(...)
//Endpoint-level
app.get('/apple', middleware1, middleware2, middleware3);
app.use('/apple', middleware1, middleware2, middleware3);
router.get('/apple', middleware1, middleware2, middleware3);
//error handler
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Server side error!');
});
//plugin
app.use(express.static('public'));
app.use(cookieParser());
route()
methodapp.get ('/apple', function (req, res) { /*...*/ });
app.post('/apple', function (req, res) { /*...*/ });
app.put ('/apple', function (req, res) { /*...*/ });
//the above code can be written in this way:
app.route('/apple')
.get (function (req, res) { /*...*/ })
.post(function (req, res) { /*...*/ })
.put (function (req, res) { /*...*/ });
//apple.js
//Definition
var express = require('express');
var router = express.Router();
// middleware only for this router
router.use(function (req, res, next) { /*...*/ next(); });
// endpoints only for this router
router.get('/', function(req, res) { /*...*/ });
router.get('/apple', function(req, res) { /*...*/ });
module.exports = router;
//Usage
var apple = require('./apple')
// /public and /public/apple
app.use('/public', apple);
req.path
req.ip
req.get()
req.params
req.body
res.download()
: downloading a fileres.end()
: end of responseres.json()
: JSON answerres.jsonp()
: JSON answer in JSONP formatres.redirect()
: redirectionres.render()
: displaying a view templateres.send()
: different kind of answersres.sendFile()
: reading and outputing a fileexpress.static(root [, options])
public/apple.html
file: /apple.html
app.use(express.static('public'));
app.set('views', './views');
app.set('view engine', 'ejs')
The template
<% code %>
<%= value, helper %>
<%- raw (unescaped) HTML %>
Hello <%= name %>!
Displaying a template (rendering)
// Rendering a view
var express = require('express');
var app = express();
// view engine setup
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.get('/main', function (req, res) {
res.render('main', {
name: 'Győző'
});
});
EJS include
<!-- including the content of header.ejs and footer.ejs -->
<% include header %>
Hello <%= name %>!
<% include footer %>
express-partials module
var express = require('express');
var partials = require('express-partials');
var app = express();
// view engine setup
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(partials());
app.get('/main', function (req, res) {
res.render('main');
});
layout.ejs
<!DOCTYPE html><title>EJS</title>
<h1>Partials</h1>
<hr>
<div>
<%- body %>
</div>
<hr>
Footer
main.ejs
Hello <%= name %>!
req.params.parameterName
// GET /user/adam
app.get('/user/:name', function (req, res) {
var name = req.params.name; // => adam
//...
});
//Parameter middleware
router.param('name', function (req, res, next, name, paramName) {
console.log('paramName' + ': ' + name);
next();
})
app.get('/user/:name', function (req, res) {
var name = req.params.name;
//...
});
req.query.parameterName
// GET /users?id=42&ref=45428174v24t2
app.get('/users', function (req, res) {
console.log(req.query);
var id = req.query.id;
var ref = req.query.ref;
})
req.body.parameterName
npm install body-parser --save
var bodyParser = require('body-parser');
//...
app.use(bodyParser.urlencoded({ extended: false }));
//...
// POST /users
app.post('/users', function(req, res) {
var firstName = req.body.firstname;
var lastName = req.body.lastname;
//...
});
POST-REDIRECT-GET method
express-validator
module
var expressValidator = require('express-validator');
app.use(express.bodyParser());
app.use(expressValidator());
app.post('/', function(req, res) {
req.checkBody('age', 'Invalid age').notEmpty().isInt();
var errors = req.validationErrors();
if (errors) {
//error handling
} else {
//success branch
}
});
Installation (express-session
)
npm install express-session --save
Usage
var session = require('express-session');
app.use(session({
cookie: { maxAge: 60000 },
secret: 'secret code',
resave: false,
saveUninitialized: false,
}));
app.get('/', function (req, res) {
// Read
req.session.parameter
// Write
req.session.parameter = value;
});
app.get('/', function (req, res) {
var sess = req.session;
var cnt = 0;
if (sess.cnt) {
cnt = sess.cnt;
}
cnt++;
sess.cnt = cnt;
res.render('counter', {
cnt: cnt
});
});
connect-flash
modulenpm install connect-flash --save
var flash = require('connect-flash');
app.use(flash());
app.get('/', function (req, res) {
// Read
req.flash(type);
// Write
req.flash(type, msg);
});
fs.readFile()
fs.writeFile()
fs.readFileSync()
fs.writeFileSync()
npm install --save nedb
npm install passport --save
var passport = require('passport');
Installing
npm install passport-<strategy> --save
Using
var Strategy = require('passport-<strategy>');
passport.use([name, ] new Strategy([options, ]
function(username, password, done) {
// Validating username and password
// Returning the result
return done(err); //Error
return done(null, false, { message: 'Üzenet' }); //Authentication failed
return done(null, user); //Successful authentication, giving back the uesr object
}
));
//Passport middlewares
app.use(passport.initialize());
//Using sessions (optional)
app.use(passport.session());
Deciding what to store in the session
// Serialization to the session
passport.serializeUser(function(user, done) {
done(null, <data stored in the session>);
});
// Recovery from the session
passport.deserializeUser(function(obj, done) {
done(null, <the expected user object>);
});
passport.authenticate()
method on endpoints
// Redirection with parameters
app.post('/signup', passport.authenticate(<strategy>, {
successRedirect: '/login',
failureRedirect: '/login/signup',
failureFlash: true, // req.flash() method is needed!
failureMessage: "Bad credentials", // optional default message
badRequestMessage: 'Missing credentials', // missing authentication data message
}));
// With callback function
app.post('/login', passport.authenticate(<strategy>),
function(req, res) {
// To be called on successful authentication
// `req.user` is the authenticated user
res.redirect('/users/' + req.user.username);
});
req.logout()
Access management
What kind of resources an authenticated user can access?
Multiple level:
Grouping users: roles
Typically on endpoint middlewares.
req.isAuthenticated()
connect-ensure-login
moduleacl
moduleThe form
GET /login
<!doctype html><title>Login</title>
<form action="/login" method="post">
<div>
<label>Username:</label>
<input type="text" name="username"/>
</div>
<div>
<label>Password:</label>
<input type="password" name="password"/>
</div>
<div>
<input type="submit" value="Log In"/>
</div>
</form>
Server side logic: using in-memory credentials
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var credentials = {
'user1': 'user1',
'a': 'a',
'user3': 'user3',
};
passport.use('local', new LocalStrategy(
function(username, password, done) {
// console.log(username, password);
if (!credentials[username]) {
return done(null, false, { message: 'Incorrect username.' });
}
if (credentials[username] !== password) {
return done(null, false, { message: 'Incorrect password.' });
}
var user = {
id: username,
username: username
};
return done(null, user);
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
var user = credentials[id];
done(null, user);
});
// route middleware to make sure
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/login');
}
app.use(passport.initialize());
app.use(passport.session());
app.get('/vedett', isLoggedIn, function (req, res) {
res.render('vedett');
});
app.get('/login', function (req, res) {
res.render('login');
})
app.post('/login',
passport.authenticate('local', { successRedirect: '/vedett',
failureRedirect: '/login' })
);
Server side logic: using file
var Datastore = require('nedb'),
db = new Datastore({ filename: 'credentials.nedb', autoload: true });
passport.use('local', new LocalStrategy(
function(username, password, done) {
db.find({username: username}, function (err, docs) {
if (docs.length === 0) {
return done(null, false, { message: 'Incorrect username.' });
}
var user = docs[0];
if (user.password !== password) {
console.log(1);
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
db.findOne({_id: id}, function (err, user) {
done(null, user);
});
});
//Registering two default users
app.get('/fill', function (req,res) {
db.insert({
username: 'a',
password: 'a'
});
db.insert({
username: 'b',
password: 'b'
});
res.end();
})