guide to node.js: basic to advanced

98
Node.js Workshops

Upload: espeo-software

Post on 13-Apr-2017

470 views

Category:

Software


0 download

TRANSCRIPT

Node.jsWorkshops

npm initit creates basic package.json file

name: heroes

name: heroesversion: 1.0.0

name: heroesversion: 1.0.0

description: heroes app

name: heroesversion: 1.0.0

description: heroes app

entry point: index.js

name: heroesversion: 1.0.0

description: heroes app

entry point: index.jstest command: [ENTER]

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]

Is it ok?: [ENTER]

Let's install our first module!

npm install express --save

{ "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

In package.json we pointed index.js

This is our inital script

So! Let's create it

touch index.js

So! Let's create it

touch index.js

Open index.js

var express = require('express'); var app = express();

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);

Open browser and go to:localhost:3003

Open browser and go to:localhost: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

Much better

but hey, I like colors

 npm install terminal-colors --save

but hey, I like colors

Oh yea!

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

Nice!Looks like we have basic node.js structure

Nice!Looks like we have basic node.js structure

Let's interact withsome database

npm install pg pg-hstore --save

But wait, let's not installPostgres locally

Let's use Docker!

Let's use Docker!

docker-machine start defaulteval $(docker-machine env default)

docker-machine start defaulteval $(docker-machine env default)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-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

You know what? We have postgres!!

For postgress weneed some config

So, let's use  sequelize-cli to

configure it

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"

Update database

node_modules/sequelize-cli/bin/sequelize db:migrate

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()

mean?

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

And send something usingPostman

We should get

Alright. But come back to index.js

What does  

require('babel-core/register');

mean?

It means we can use ES6 instead of ES5

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

import express from 'express';

var express = require('express');

export default router;

module.exports = router;

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)});

.then((user) => { return user.get({token: token}); }

.then(user => user.get({token}))

Let's create someauthentication

npm install passport passport-http-bearerpassport-local bcrypt-nodejs --save

Create User model

node_modules/sequelize-cli/bin/sequelize model:create--name User--attributes "email:string, password:string, token:string"

Create Middleware

mkdir middlewarecd middleware

touch passport.js

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

Bearer tokenstrategy

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

Testing

depsnpm install --save-dev

supertest expect.js mocha

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 "},

test foldermkdir integrationTest

cd integrationTest

touch offers.js

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(); }); } });

Frontend

git checkout newerstuff frontend gulpfile.js

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 +

Add some logging stuffnpm install --save morgan

winston

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