guide to node.js: basic to advanced
TRANSCRIPT
name: heroesversion: 1.0.0
description: heroes app
entry point: index.jstest command: [ENTER]git repository: [ENTER]
name: heroesversion: 1.0.0
description: heroes app
entry point: index.jstest command: [ENTER]git repository: [ENTER]
keywords: [ENTER]
name: heroesversion: 1.0.0
description: heroes app
entry point: index.jstest command: [ENTER]git repository: [ENTER]
keywords: [ENTER]license: [ENTER]
{ "name": "node-workshop", "version": "1.0.0", "description": "heroes app", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "ssuperczynski <[email protected]> (espeo.eu)", "license": "ISC", "dependencies": { "express": "̂4.13.4" } }
Our module has been successfully installed
Open index.js
var express = require('express'); var app = express();
app.get('/', function (req, res) { res.send('viewing single offer'); });
Open index.js
var express = require('express'); var app = express();
app.get('/', function (req, res) { res.send('viewing single offer'); });
app.listen(3003);
var express = require('express'); var app = express();
app.get('/', function (req, res) { res.send('viewing single offer'); });
app.listen(3004, function () { console.log("server started at 3004 port"); });
But we don't know ifserver works or not
Let's refactor index.js
var express = require('express'); var app = express();
app.get('/', getOffer);
function getOffer(req, res) { res.send('viewing single offer'); }
app.listen(3004, function () { console.log("server started at 3004 port"); });
index.js
Let's refactor index.js further
function getOffer(req, res) { res.send('viewing single offer'); }
module.exports = getOffer;
controller/OfferController.js
Let's refactor index.js further
var express = require('express'); var app = express(); var getOffer = require('./controllers/OfferController');
app.get('/', getOffer);
app.listen(3004);
index.js
docker-machine start defaulteval $(docker-machine env default)
version: '2' services: postgres: image: postgres ports: - "5432:5432" environment: POSTGRES_PASSWORD: mypassword
vi docker-compose.yml
docker-machine start defaulteval $(docker-machine env default)
version: '2' services: postgres: image: postgres ports: - "5432:5432" environment: POSTGRES_PASSWORD: mypassword
vi docker-compose.yml
docker-compose build docker-compose up
Creating our model using
npm install sequelize --savenpm install sequelize-cli --savenode_modules/sequelize-cli/bin/sequelize init
Creating basic schema
node_modules/sequelize-cli/bin/sequelize model:create--name Offer--attributes "content:string, title:string"
Let's add more methods toOfferController.js
function getOffer(req, res) { models.Offer.findAll() .then((offers) => { res.send(offers); }) .catch(() => {res.send('Error')}); }
module.exports = getOffer;
controller/OfferController.js
But what doesmodels.Offer.findAll()
var sequelize = new Sequelize('postgres://user:[email protected]:5432/dbname');
var Offer = sequelize.define('Offer', { title: {type: sequelize.STRING, allowNull: false}, content: {type: sequelize.STRING, allowNull: false} }, {});
export default Offer;
models/offer.jsmean?
But what doesmodels.Offer.findAll()
mean?
function createOffer(req, res) { models.Offer.create({ content: req.body.content, title: req.body.title }) .then((offer) => { res.send(offer); }) .catch(() => {res.send('Error')}); }
module.exports = getOffer;
controller/OfferController.js
Add new method to index.js
var express = require('express'); var app = express(); var indexAction = require('./controllers/OfferController');
app.get('/', getOffer);
app.post('/', createOffer);
app.listen(3004);
index.js
Add new method to index.js
function createOffer(req, res) { Offer.create({ content: req.body.content, title: req.body.title }) .then((offer) => { res.send(offer); }) .catch((err) => {res.send(err)}); }
controller/OfferController.js
import express from 'express'; import OffersController from './OffersController'; import UsersController from './UsersController';
let router = express.Router();
router.use('/offers', OffersController); router.use('/users', UsersController);
module.exports = router;
index.js
Offer.create({ content: req.body.content, title: req.body.title }) .then(offer => res.send(offer)) .catch(err => res.send(err));
Offer.create({ content: req.body.content, title: req.body.title }) .then(function(offer) { res.send(offer); }) .catch(function(err) { res.send(err)});
Create User model
node_modules/sequelize-cli/bin/sequelize model:create--name User--attributes "email:string, password:string, token:string"
Register passport strategy
import passport from 'passport'; import local from 'passport-local';
passport.use('local', new local.Strategy(options, callback));
export default passport;
import bcrypt from 'bcrypt-nodejs'; import Promise from 'Bluebird';
instanceMethods: { comparePassword: function (hash) { var userPassword = this.password; var user = this; return new Promise((resolve, reject) => { Promise.promisify(bcrypt.compare)(hash, userPassword) .then((result) => { resolve([result, user]); }, (err) => { reject(err); }); }); } },
Update User model
hooks: { beforeCreate: (user, options, cb) => { Promise.promisify(bcrypt.genSalt)(10) .then((salt) => { return Promise.promisify(bcrypt.hash)(user.password, salt, }) .then((hash) => { user.password = hash; cb(null, options); }); } }
Update User model
/// ....
import { User } from '../models'; import Promise from 'bluebird';
var options = { usernameField: 'email', passwordField: 'password' };
var onLogIn = (email, password, done) => { User.findOne({where: {email}}) .then(user => user ? user.comparePassword(password) : Promise.reject(new Promise.CancellationError ) .spread((isMatch, user) => isMatch ? done(null, user) : Promise.reject(new Promise.CancellationError('Wrong email or password' ) .catch(Promise.CancellationError, info => done(null, false, info)) .catch(err => done(err)); };
Add callback to strategy
//controllers/UsersController.js
import express from 'express'; import {User} from '../models'; import passport from 'passport';
let router = express.Router({mergeParams: true});
router.post('/signUp', signUp); router.post('/logIn', logIn);
export default router;
Create login and register endpoints
function signUp(req, res) { User.create({ email: req.body.email, password: req.body.password }).then(user => res.send({email: user.email })) .catch(err => res.send(err)); }
function logIn(req, res, next) { passport.authenticate('local', (err, user, info) => { if (err) { return res.send(err); } if (!user) { return res.send(info.toString()); } return res.send({user}); })(req, res, next); }
Add child router to main router
// controllers/index.jsimport UsersController from './UsersController';
router.use('/users', UsersController);
import passport from './middleware/passport'; app.use(passport.initialize());
Register passport as a middleware:app.js
Add token helper
// helpers/token.js
import crypto from 'crypto';
import Promise from 'bluebird';
export default function generate() {
return new Promise((resolve, reject) => {
Promise.promisify(crypto.randomBytes)(48).then((buff) => {
resolve(buff.toString('hex'));
}).catch(err => reject(err));
});
}
Modify local-login strategy
User.findOne({where: {email}}) .then((user) => { return user ? user.comparePassword(password) : Promise.reject(new Promise. } ) .spread((isMatch, user) => isMatch ? generateToken() .then(token => user.update({token})) .then(() => done(null, user.token)) : Promise.reject(new Promise.CancellationError('Wrong email or password')) ) .catch(Promise.CancellationError, info => done(null, false, info)) .catch(err => done(err));
Modify UsersController
function logIn(req, res, next) { passport.authenticate('local', (err, token, info) => { if (err) { return res.send(err); } if (!token) { return res.send(info.toString()); } return res.send({token}); })(req, res, next); }
// middleware/passport.js
import generateToken from '../helpers/token';
import token from 'passport-http-bearer';
passport.use('token', new token.Strategy((token, done) => { User.findOne({where: {token}}) .then(user => user ? done(null, user, {scope: 'all'}) : done(null .catch(err => done(err)); }));
export var tokenAuthentication = passport.authenticate('token', {session: false
Add token strategy
function singleOffer(req, res) { Offer.findById(req.params.id) .then(offer => res.send(offer)) .catch(err => res.send(err)); }
function RespondToOffer(req, res) { OfferResponse.create({ OfferId: req.body.id, email: req.body.email, content: req.body.content }) .then(response => res.send(response)) .catch(err => res.send(err)); }
router.get('/:id', singleOffer); router.post('/respond', RespondToOffer);
Add new Offer endpoints
//controllers/OffersController.js
import {tokenAuthentication} from '../middleware/passport';router.post('/respond', tokenAuthentication, RespondToOffer);
Restrict access to some route
// controllers/UsersController.js
function logOut(req, res) { User.findOne({ where: {token: req.user.token}}) .then((user) => { return user.update({token: null}); }) .then(() => { res.send('Logged out.'); }) .catch(err => res.send(err)); }
router.delete('/logOut', tokenAuthentication, logOut);
Add log out endpoint
package.json"scripts": { "start": "node bin/index.js", "build": "gulp", "test": "npm run test-integration", "test-integration": "NODE_ENV=test mocha --compilers js:babel-core/register integrationTests "},
integrationTest/offers.js
var request = require('supertest'); var expect = require('expect.js'); var app = require('../bin/index'); var Bluebird = require('bluebird'); var models = require('../models');
describe('offerController', function () { beforeEach(function () { return Bluebird.all([ models.Offer.destroy({truncate: true}), models.OfferResponse.destroy({truncate: true}), models.User.destroy({truncate: true}) ]); });
it('should have /all endpoint and return with 200', function (done) { request(app).get('/offers').expect(200, done); }); });
it('should login and respond to the offer', function (done) { var token = '';
var newUser = { email: '[email protected]', password: 'test' };
models.User.create(newUser).then(() => { request(app).post('/users/logIn') .type('form') .send(newUser) .expect(200, (err, result) => { token = result.body.token; createSomeOffer(); }); });
function createSomeOffer() { return request(app).post('/offers/') .type('form') .send({content: 'you have to code in XML', title: 'some programmer'}) .expect(200, respondToOffer); }
...
function respondToOffer(err, result) { if (err) done(err); request(app).post('/offers/respond') .set('Authorization', 'Bearer ' + token) .type('form') .send({id: result.body.id, email: '[email protected]', content: 'i want this job' .expect(200, onResponseCreate); }
function onResponseCreate() { request(app).get('/offers').expect(200, function (err, result) { if (err) done(err); expect(result.body[0].OfferResponses[0].email).to.be('[email protected]'); expect(result.body[0].OfferResponses[0].content).to.be('i want this job') done(); }); } });
Serving static files
import path from 'path';
app .use(bodyParser.urlencoded({extended: true})) .use(bodyParser.json()) .use(passport.initialize()) .use('/', router) .use('/static', express.static('static'));
Serve index.html
// controllers/index.js
router.get('/', (req, res) => res.sendFile(path.join(__dirname +
Log requests
import morgan from 'morgan';
import fs from 'fs';
var accessLogStream = fs.createWriteStream(__dirname + '/access.log'
app .use(morgan('dev', {stream: accessLogStream})) .use(morgan('dev'))
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798