├── .gitignore ├── .nvmrc ├── Chapter_01 └── hello-world │ ├── app.js │ └── package.json ├── Chapter_02 ├── mustache │ ├── mustache-test.js │ ├── package-lock.json │ └── package.json └── random-integer │ ├── print-three-random-integers.js │ └── random-integer.js ├── Chapter_03 ├── guestbook │ ├── app.js │ ├── package.json │ └── views │ │ ├── 404.ejs │ │ ├── footer.ejs │ │ ├── header.ejs │ │ ├── index.ejs │ │ └── new-entry.ejs ├── hello-world │ ├── app-morgan-logging.js │ ├── app-simple-logging.js │ ├── app-simple.js │ ├── app.js │ ├── cool-facts.txt │ ├── package.json │ └── route-example.js ├── statics │ ├── app.js │ ├── package.json │ └── public │ │ └── file.txt └── views-example │ ├── app.js │ ├── package.json │ └── views │ └── index.ejs ├── Chapter_04 ├── error-stack │ ├── app.js │ └── package.json └── static-file-fun │ ├── app.js │ ├── first-version.js │ ├── package.json │ └── static │ └── cool.txt ├── Chapter_05 └── temperature-by-zip-code │ ├── app.js │ ├── package.json │ ├── public │ ├── the.css │ └── the.js │ └── views │ ├── 404.ejs │ ├── footer.ejs │ ├── header.ejs │ └── index.ejs ├── Chapter_06 └── random-number-api │ ├── app.js │ └── package.json ├── Chapter_08 └── learn-about-me │ ├── README.md │ ├── app.js │ ├── models │ └── user.js │ ├── package.json │ ├── routes.js │ ├── setuppassport.js │ └── views │ ├── _footer.ejs │ ├── _header.ejs │ ├── edit.ejs │ ├── index.ejs │ ├── login.ejs │ ├── profile.ejs │ └── signup.ejs ├── Chapter_09 ├── simple_tests │ ├── .gitignore │ ├── capitalize.js │ ├── package.json │ └── test │ │ ├── capitalize.js │ │ └── mocha.opts └── whats_my_useragent │ ├── .gitignore │ ├── app.js │ ├── package.json │ ├── test │ ├── html.js │ └── txt.js │ └── views │ └── index.ejs ├── Chapter_10 ├── csrf-example │ ├── app.js │ ├── package.json │ └── views │ │ └── index.ejs ├── forever-example │ ├── app.js │ └── package.json └── print-queries │ ├── app.js │ └── package.json ├── Chapter_11 ├── grunt-examples │ ├── .gitignore │ ├── Gruntfile.js │ ├── app.js │ ├── my_css │ │ └── main.less │ ├── my_javascripts │ │ └── main.js │ └── package.json └── heroku-app │ ├── .gitignore │ ├── Procfile │ ├── app.js │ └── package.json ├── Chapter_12 └── express-generated-app │ ├── .gitignore │ ├── app.js │ ├── bin │ └── www │ ├── package.json │ ├── public │ └── stylesheets │ │ └── style.css │ ├── routes │ ├── index.js │ └── users.js │ └── views │ ├── error.jade │ ├── index.jade │ └── layout.jade ├── README.md └── Vagrantfile /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant/ 2 | 3 | node_modules 4 | *.log 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v4.2 2 | -------------------------------------------------------------------------------- /Chapter_01/hello-world/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | 3 | var app = express(); 4 | 5 | app.get("/", function(request, response) { 6 | response.send("Hello world!"); 7 | }); 8 | 9 | app.listen(3000, function() { 10 | console.log("Express app started on port 3000."); 11 | }); 12 | -------------------------------------------------------------------------------- /Chapter_01/hello-world/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "express": "^5.0.0-alpha.2" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Chapter_02/mustache/mustache-test.js: -------------------------------------------------------------------------------- 1 | var Mustache = require("mustache"); 2 | var result = Mustache.render("Hi {{first}} {{last}}!", { 3 | first: "Nicolas", 4 | last: "Cage" 5 | }); 6 | 7 | console.log(result); -------------------------------------------------------------------------------- /Chapter_02/mustache/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "mustache": { 6 | "version": "2.3.0", 7 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz", 8 | "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter_02/mustache/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "mustache": "^2.3.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Chapter_02/random-integer/print-three-random-integers.js: -------------------------------------------------------------------------------- 1 | var randomInt = require("./random-integer"); 2 | console.log(randomInt()); 3 | console.log(randomInt()); 4 | console.log(randomInt()); 5 | -------------------------------------------------------------------------------- /Chapter_02/random-integer/random-integer.js: -------------------------------------------------------------------------------- 1 | var MAX = 100; 2 | 3 | function randomInteger() { 4 | return Math.floor((Math.random() * MAX)); 5 | } 6 | 7 | module.exports = randomInteger; 8 | -------------------------------------------------------------------------------- /Chapter_03/guestbook/app.js: -------------------------------------------------------------------------------- 1 | var http = require("http"); 2 | var path = require("path"); 3 | var express = require("express"); 4 | var logger = require("morgan"); 5 | var bodyParser = require("body-parser"); 6 | 7 | var app = express(); 8 | 9 | var entries = []; 10 | app.locals.entries = entries; 11 | 12 | app.use(logger("dev")); 13 | 14 | app.set("views", path.resolve(__dirname, "views")); 15 | app.set("view engine", "ejs"); 16 | 17 | app.use(bodyParser.urlencoded({ extended: false })); 18 | 19 | app.get("/", function(req, res) { 20 | res.render("index"); 21 | }); 22 | 23 | app.get("/new-entry", function(req, res) { 24 | res.render("new-entry"); 25 | }); 26 | 27 | app.post("/new-entry", function(req, res) { 28 | if (!req.body.title || !req.body.body) { 29 | res.status(400).send("Entries must have a title and a body."); 30 | return; 31 | } 32 | entries.push({ 33 | title: req.body.title, 34 | body: req.body.body, 35 | published: new Date() 36 | }); 37 | res.redirect("/"); 38 | }); 39 | 40 | app.use(function(req, res) { 41 | res.status(404).render("404"); 42 | }); 43 | 44 | http.createServer(app).listen(3000, function() { 45 | console.log("Guestbook app started."); 46 | }); 47 | -------------------------------------------------------------------------------- /Chapter_03/guestbook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-guestbook", 3 | "private": true, 4 | "scripts": { 5 | "start": "node app" 6 | }, 7 | "dependencies": { 8 | "body-parser": "^1.13.2", 9 | "ejs": "^2.3.3", 10 | "express": "^5.0.0-alpha.2", 11 | "morgan": "^1.6.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Chapter_03/guestbook/views/404.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 |

404! Page not found.

3 | <% include footer %> -------------------------------------------------------------------------------- /Chapter_03/guestbook/views/footer.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Chapter_03/guestbook/views/header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Express Guestbook 6 | 7 | 8 | 9 |

10 | Express Guestbook 11 | 12 | Write in the guestbook 13 | 14 |

15 | -------------------------------------------------------------------------------- /Chapter_03/guestbook/views/index.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | <% if (entries.length) { %> 3 | <% entries.forEach(function(entry) { %> 4 |
5 |
6 |
7 | <%= entry.published %> 8 |
9 | <%= entry.title %> 10 |
11 |
12 | <%= entry.body %> 13 |
14 |
15 | <% }) %> 16 | <% } else { %> No entries! Add one! 17 | <% } %> 18 | <% include footer %> 19 | -------------------------------------------------------------------------------- /Chapter_03/guestbook/views/new-entry.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | 3 |

Write a new entry

4 | 5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 |
17 |
18 | 19 | <% include footer %> 20 | -------------------------------------------------------------------------------- /Chapter_03/hello-world/app-morgan-logging.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var logger = require("morgan"); 3 | var http = require("http"); 4 | 5 | var app = express(); 6 | 7 | app.use(logger("short")); 8 | 9 | app.use(function(request, response) { 10 | response.writeHead(200, { "Content-Type": "text/plain" }); 11 | response.end("Hello, World!"); 12 | }); 13 | 14 | http.createServer(app).listen(3000); 15 | -------------------------------------------------------------------------------- /Chapter_03/hello-world/app-simple-logging.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var http = require("http"); 3 | 4 | var app = express(); 5 | 6 | app.use(function(request, response, next) { 7 | console.log("In comes a " + request.method + " to " + request.url); 8 | next(); 9 | }); 10 | 11 | app.use(function(request, response) { 12 | response.writeHead(200, { "Content-Type": "text/plain" }); 13 | response.end("Hello, World!"); 14 | }); 15 | 16 | http.createServer(app).listen(3000); 17 | -------------------------------------------------------------------------------- /Chapter_03/hello-world/app-simple.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var http = require("http"); 3 | 4 | var app = express(); 5 | 6 | app.use(function(request, response) { 7 | console.log("In comes a request to: " + request.url); 8 | response.end("Hello, World!"); 9 | }); 10 | 11 | http.createServer(app).listen(3000); 12 | -------------------------------------------------------------------------------- /Chapter_03/hello-world/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var logger = require("morgan"); 3 | var http = require("http"); 4 | 5 | var app = express(); 6 | 7 | app.use(logger("short")); 8 | 9 | app.use(function(request, response, next) { 10 | var minute = (new Date()).getMinutes(); 11 | if ((minute % 2) === 0) { 12 | next(); 13 | } else { 14 | response.statusCode = 403; 15 | response.end("Not authorized."); 16 | } 17 | }); 18 | 19 | app.use(function(request, response) { 20 | response.writeHead(200, { "Content-Type": "text/plain" }); 21 | response.end("Hello, World!"); 22 | }); 23 | 24 | http.createServer(app).listen(3000); 25 | -------------------------------------------------------------------------------- /Chapter_03/hello-world/cool-facts.txt: -------------------------------------------------------------------------------- 1 | - dogs are cool 2 | - cats are cool 3 | - ??? 4 | -------------------------------------------------------------------------------- /Chapter_03/hello-world/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "express": "^5.0.0-alpha.2", 8 | "morgan": "^1.6.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_03/hello-world/route-example.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); var path = require("path"); var http = require("http"); var app = express(); app.get("/", function(request, response) { response.end("Welcome to my homepage!"); }); app.get("/about", function(request, response) { response.end("Welcome to the about page!"); }); app.get("/weather", function(request, response) { response.end("The current weather is NICE."); }); app.get("/hello/:who", function(request, response) { response.end("Hello, " + request.params.who + "."); // Fun fact: this has some security issues, which we’ll get to! }); app.get("/redirect_home", function (request, response) { response.redirect("/"); }); app.get("/sendfile", function (request, response) { var filePath = path.resolve(__dirname, "cool-facts.txt"); response.sendFile(filePath); }); app.use(function(request, response) { response.statusCode = 404; response.end("404!"); }); http.createServer(app).listen(3000); -------------------------------------------------------------------------------- /Chapter_03/statics/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var path = require("path"); 3 | var http = require("http"); 4 | 5 | var app = express(); 6 | 7 | var publicPath = path.resolve(__dirname, "public"); 8 | app.use(express.static(publicPath)); 9 | 10 | app.use(function(request, response) { 11 | response.writeHead(200, { "Content-Type": "text/plain" }); 12 | response.end("Looks like you didn't find a static file."); 13 | }); 14 | 15 | http.createServer(app).listen(3000); 16 | -------------------------------------------------------------------------------- /Chapter_03/statics/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "express": "^5.0.0-alpha.2", 8 | "morgan": "^1.6.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_03/statics/public/file.txt: -------------------------------------------------------------------------------- 1 | This is a sample static file! 2 | -------------------------------------------------------------------------------- /Chapter_03/views-example/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); var http = require("http"); var path = require("path"); var app = express(); app.set("views", path.resolve(__dirname, "views")); app.set("view engine", "ejs"); app.get("/", function(request, response) { response.render("index", { message: "Hey everyone! This is my webpage." }); }); http.createServer(app).listen(3000); -------------------------------------------------------------------------------- /Chapter_03/views-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "ejs": "^2.3.3", 8 | "express": "^5.0.0-alpha.2", 9 | "morgan": "^1.6.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter_03/views-example/views/index.ejs: -------------------------------------------------------------------------------- 1 | Hello, world <%= message %> -------------------------------------------------------------------------------- /Chapter_04/error-stack/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var morgan = require("morgan"); 3 | 4 | var app = express(); 5 | 6 | app.use(morgan("dev")); 7 | 8 | app.use(function(req, res, next) { 9 | if (req.url === "/") { 10 | next(); 11 | } else if (req.url === "/throw") { 12 | throw new Error("Gimme that error"); 13 | } else { 14 | next("You didn't visit the root!"); 15 | } 16 | }); 17 | 18 | app.use(function(req, res) { 19 | res.send("Welcome to the homepage."); 20 | }); 21 | 22 | app.use(function(err, req, res, next) { 23 | console.error(err); 24 | res.status(500); 25 | next(err); 26 | }); 27 | 28 | app.use(function(err, req, res, next) { 29 | res.send("Got an error: " + err); 30 | }); 31 | 32 | app.listen(3000, function() { 33 | console.log("App started"); 34 | }); 35 | -------------------------------------------------------------------------------- /Chapter_04/error-stack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "express": "^5.0.0-alpha.2", 8 | "morgan": "^1.5.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_04/static-file-fun/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var morgan = require("morgan"); 3 | var path = require("path"); 4 | 5 | var app = express(); 6 | 7 | app.use(morgan("short")); 8 | 9 | var staticPath = path.join(__dirname, "static"); 10 | app.use(express.static(staticPath)); 11 | 12 | app.use(function(req, res) { 13 | res.status(404); 14 | res.send("File not found!"); 15 | }); 16 | 17 | app.listen(3000, function() { 18 | console.log("App started on port 3000"); 19 | }); 20 | -------------------------------------------------------------------------------- /Chapter_04/static-file-fun/first-version.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var path = require("path"); 3 | var fs = require("fs"); 4 | 5 | var app = express(); 6 | 7 | app.use(function(req, res, next) { 8 | console.log("Request IP: " + req.url); 9 | console.log("Request date: " + new Date()); 10 | next(); 11 | }); 12 | 13 | app.use(function(req, res, next) { 14 | var filePath = path.join(__dirname, "static", req.url); 15 | fs.stat(filePath, function(err, fileInfo) { 16 | if (err) { 17 | next(); 18 | return; 19 | } 20 | 21 | if (fileInfo.isFile()) { 22 | res.sendFile(filePath); 23 | } else { 24 | next(); 25 | } 26 | }); 27 | }); 28 | 29 | app.use(function(req, res) { 30 | res.status(404); 31 | res.send("File not found!"); 32 | }); 33 | 34 | app.listen(3000, function() { 35 | console.log("App started on port 3000"); 36 | }); 37 | -------------------------------------------------------------------------------- /Chapter_04/static-file-fun/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "express": "^5.0.0-alpha.2", 8 | "morgan": "^1.6.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_04/static-file-fun/static/cool.txt: -------------------------------------------------------------------------------- 1 | This is a sample static file! 2 | -------------------------------------------------------------------------------- /Chapter_05/temperature-by-zip-code/app.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var express = require("express"); 3 | var zipdb = require("zippity-do-dah"); 4 | var ForecastIo = require("forecastio"); 5 | 6 | var app = express(); 7 | var weather = new ForecastIo("YOUR FORECAST.IO API KEY OR DARKSKY.NET API KEY HERE"); 8 | 9 | app.use(express.static(path.resolve(__dirname, "public"))); 10 | 11 | app.set("views", path.resolve(__dirname, "views")); 12 | app.set("view engine", "ejs"); 13 | 14 | app.get("/", function(req, res) { 15 | res.render("index"); 16 | }); 17 | 18 | app.get(/^\/(\d{5})$/, function(req, res, next) { 19 | var zipcode = req.params[0]; 20 | var location = zipdb.zipcode(zipcode); 21 | if (!location.zipcode) { 22 | next(); 23 | return; 24 | } 25 | 26 | var latitude = location.latitude; 27 | var longitude = location.longitude; 28 | 29 | weather.forecast(latitude, longitude, function(err, data) { 30 | if (err) { 31 | next(); 32 | return; 33 | } 34 | 35 | res.json({ 36 | zipcode: zipcode, 37 | temperature: data.currently.temperature 38 | }); 39 | }); 40 | }); 41 | 42 | app.use(function(req, res) { 43 | res.status(404).render("404"); 44 | }); 45 | app.listen(3000); 46 | -------------------------------------------------------------------------------- /Chapter_05/temperature-by-zip-code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "temperature-by-zip", 3 | "private": true, 4 | "scripts": { 5 | "start": "node app.js" 6 | }, 7 | "dependencies": { 8 | "ejs": "^2.3.1", 9 | "express": "5.0.0-alpha.2", 10 | "forecastio": "^0.2.0", 11 | "zippity-do-dah": "0.0.x" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Chapter_05/temperature-by-zip-code/public/the.css: -------------------------------------------------------------------------------- 1 | html { 2 | display: table; 3 | width: 100%; 4 | height: 100%; 5 | } 6 | body { 7 | display: table-cell; 8 | vertical-align: middle; 9 | text-align: center; 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_05/temperature-by-zip-code/public/the.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | var $h1 = $("h1"); 3 | var $zip = $("input[name='zip']"); 4 | $("form").on("submit", function(event) { 5 | event.preventDefault(); 6 | var zipCode = $.trim($zip.val()); 7 | $h1.text("Loading..."); 8 | var request = $.ajax({ 9 | url: "/" + zipCode, 10 | dataType: "json" 11 | }); 12 | request.done(function(data) { 13 | var temperature = data.temperature; 14 | $h1.text("It is " + temperature + "º in " + zipCode + "."); 15 | }); 16 | request.fail(function() { 17 | $h1.text("Error!"); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /Chapter_05/temperature-by-zip-code/views/404.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | 3 |

404 error! File not found.

4 | 5 | <% include footer %> 6 | -------------------------------------------------------------------------------- /Chapter_05/temperature-by-zip-code/views/footer.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Chapter_05/temperature-by-zip-code/views/header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Temperature by ZIP code 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Chapter_05/temperature-by-zip-code/views/index.ejs: -------------------------------------------------------------------------------- 1 | <% include header %> 2 | 3 |

What's your ZIP code?

4 | 5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | <% include footer %> 16 | -------------------------------------------------------------------------------- /Chapter_06/random-number-api/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | 3 | var app = express(); 4 | 5 | app.get("/random/:min/:max", function(req, res) { 6 | var min = parseInt(req.params.min); 7 | var max = parseInt(req.params.max); 8 | if (isNaN(min) || isNaN(max)) { 9 | res.status(400); 10 | res.json({ error: "Bad request." }); 11 | return; 12 | } 13 | 14 | var result = Math.round((Math.random() * (max - min)) + min); 15 | 16 | res.json({ result: result }); 17 | }); 18 | 19 | app.listen(3000, function() { 20 | console.log("App started on port 3000"); 21 | }); 22 | -------------------------------------------------------------------------------- /Chapter_06/random-number-api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "random-number-api", 3 | "private": true, 4 | "scripts": { 5 | "start": "node app" 6 | }, 7 | "dependencies": { 8 | "express": "5.0.0-alpha.2" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/README.md: -------------------------------------------------------------------------------- 1 | Learn About Me 2 | ============== 3 | 4 | This example is very similar to the one in the book. The only difference is that the `mongoose` dependency has been updated to version 4 to fix some errors. 5 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/app.js: -------------------------------------------------------------------------------- 1 | var bodyParser = require("body-parser"); 2 | var cookieParser = require("cookie-parser"); 3 | var express = require("express"); 4 | var flash = require("connect-flash"); 5 | var mongoose = require("mongoose"); 6 | var passport = require("passport"); 7 | var path = require("path"); 8 | var session = require("express-session"); 9 | 10 | var setUpPassport = require("./setuppassport"); 11 | var routes = require("./routes"); 12 | 13 | var app = express(); 14 | mongoose.connect("mongodb://localhost:27017/test"); 15 | setUpPassport(); 16 | 17 | app.set("port", process.env.PORT || 3000); 18 | 19 | app.set("views", path.join(__dirname, "views")); 20 | app.set("view engine", "ejs"); 21 | 22 | app.use(express.static(path.join(__dirname, "public"))); 23 | 24 | app.use(bodyParser.urlencoded({ extended: false })); 25 | app.use(cookieParser()); 26 | 27 | app.use(session({ 28 | secret: "LUp$Dg?,I#i&owP3=9su+OB%`JgL4muLF5YJ~{;t", 29 | resave: true, 30 | saveUninitialized: true 31 | })); 32 | 33 | app.use(flash()); 34 | 35 | app.use(passport.initialize()); 36 | app.use(passport.session()); 37 | 38 | app.use(routes); 39 | 40 | app.listen(app.get("port"), function() { 41 | console.log("Server started on port " + app.get("port")); 42 | }); 43 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/models/user.js: -------------------------------------------------------------------------------- 1 | var bcrypt = require("bcrypt-nodejs"); 2 | var mongoose = require("mongoose"); 3 | 4 | var SALT_FACTOR = 10; 5 | 6 | var userSchema = mongoose.Schema({ 7 | username: { type: String, required: true, unique: true }, 8 | password: { type: String, required: true }, 9 | createdAt: { type: Date, default: Date.now }, 10 | displayName: String, 11 | bio: String 12 | }); 13 | 14 | var noop = function() {}; 15 | 16 | userSchema.pre("save", function(done) { 17 | var user = this; 18 | 19 | if (!user.isModified("password")) { 20 | return done(); 21 | } 22 | 23 | bcrypt.genSalt(SALT_FACTOR, function(err, salt) { 24 | if (err) { return done(err); } 25 | bcrypt.hash(user.password, salt, noop, function(err, hashedPassword) { 26 | if (err) { return done(err); } 27 | user.password = hashedPassword; 28 | done(); 29 | }); 30 | }); 31 | }); 32 | 33 | userSchema.methods.checkPassword = function(guess, done) { 34 | bcrypt.compare(guess, this.password, function(err, isMatch) { 35 | done(err, isMatch); 36 | }); 37 | }; 38 | 39 | userSchema.methods.name = function() { 40 | return this.displayName || this.username; 41 | }; 42 | 43 | var User = mongoose.model("User", userSchema); 44 | 45 | module.exports = User; 46 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "learn-about-me", 3 | "private": true, 4 | "scripts": { 5 | "start": "node app" 6 | }, 7 | "dependencies": { 8 | "bcrypt-nodejs": "0.0.3", 9 | "body-parser": "^1.6.5", 10 | "connect-flash": "^0.1.1", 11 | "cookie-parser": "^1.3.2", 12 | "ejs": "^1.0.0", 13 | "express": "5.0.0-alpha.2", 14 | "express-session": "^1.7.6", 15 | "mongoose": "^4.0.0", 16 | "passport": "^0.2.0", 17 | "passport-local": "^1.0.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/routes.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var passport = require("passport"); 3 | 4 | var User = require("./models/user"); 5 | var router = express.Router(); 6 | 7 | function ensureAuthenticated(req, res, next) { 8 | if (req.isAuthenticated()) { 9 | next(); 10 | } else { 11 | req.flash("info", "You must be logged in to see this page."); 12 | res.redirect("/login"); 13 | } 14 | } 15 | 16 | router.use(function(req, res, next) { 17 | res.locals.currentUser = req.user; 18 | res.locals.errors = req.flash("error"); 19 | res.locals.infos = req.flash("info"); 20 | next(); 21 | }); 22 | 23 | router.get("/", function(req, res, next) { 24 | User.find() 25 | .sort({ createdAt: "descending" }) 26 | .exec(function(err, users) { 27 | if (err) { return next(err); } 28 | res.render("index", { users: users }); 29 | }); 30 | }); 31 | 32 | router.get("/login", function(req, res) { 33 | res.render("login"); 34 | }); 35 | 36 | router.post("/login", passport.authenticate("login", { 37 | successRedirect: "/", 38 | failureRedirect: "/login", 39 | failureFlash: true 40 | })); 41 | 42 | router.get("/logout", function(req, res) { 43 | req.logout(); 44 | res.redirect("/"); 45 | }); 46 | 47 | router.get("/signup", function(req, res) { 48 | res.render("signup"); 49 | }); 50 | 51 | router.post("/signup", function(req, res, next) { 52 | 53 | var username = req.body.username; 54 | var password = req.body.password; 55 | 56 | User.findOne({ username: username }, function(err, user) { 57 | 58 | if (err) { return next(err); } 59 | if (user) { 60 | req.flash("error", "User already exists"); 61 | return res.redirect("/signup"); 62 | } 63 | 64 | var newUser = new User({ 65 | username: username, 66 | password: password 67 | }); 68 | newUser.save(next); 69 | 70 | }); 71 | }, passport.authenticate("login", { 72 | successRedirect: "/", 73 | failureRedirect: "/signup", 74 | failureFlash: true 75 | })); 76 | 77 | router.get("/users/:username", function(req, res, next) { 78 | User.findOne({ username: req.params.username }, function(err, user) { 79 | if (err) { return next(err); } 80 | if (!user) { return next(404); } 81 | res.render("profile", { user: user }); 82 | }); 83 | }); 84 | 85 | router.get("/edit", ensureAuthenticated, function(req, res) { 86 | res.render("edit"); 87 | }); 88 | 89 | router.post("/edit", ensureAuthenticated, function(req, res, next) { 90 | req.user.displayName = req.body.displayname; 91 | req.user.bio = req.body.bio; 92 | req.user.save(function(err) { 93 | if (err) { 94 | next(err); 95 | return; 96 | } 97 | req.flash("info", "Profile updated!"); 98 | res.redirect("/edit"); 99 | }); 100 | }); 101 | 102 | module.exports = router; 103 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/setuppassport.js: -------------------------------------------------------------------------------- 1 | var passport = require("passport"); 2 | var LocalStrategy = require("passport-local").Strategy; 3 | 4 | var User = require("./models/user"); 5 | 6 | module.exports = function() { 7 | 8 | passport.serializeUser(function(user, done) { 9 | done(null, user._id); 10 | }); 11 | 12 | passport.deserializeUser(function(id, done) { 13 | User.findById(id, function(err, user) { 14 | done(err, user); 15 | }); 16 | }); 17 | 18 | passport.use("login", new LocalStrategy(function(username, password, done) { 19 | User.findOne({ username: username }, function(err, user) { 20 | if (err) { return done(err); } 21 | if (!user) { 22 | return done(null, false, { message: "No user has that username!" }); 23 | } 24 | user.checkPassword(password, function(err, isMatch) { 25 | if (err) { return done(err); } 26 | if (isMatch) { 27 | return done(null, user); 28 | } else { 29 | return done(null, false, { message: "Invalid password." }); 30 | } 31 | }); 32 | }); 33 | })); 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/views/_footer.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/views/_header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Learn About Me 8 | 9 | 10 | 11 | 12 | 13 | 14 | 39 | 40 |
41 | 42 | <% errors.forEach(function(error) { %> 43 | 46 | <% }) %> 47 | 48 | <% infos.forEach(function(info) { %> 49 | 52 | <% }) %> 53 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/views/edit.ejs: -------------------------------------------------------------------------------- 1 | <% include _header %> 2 | 3 |

Edit your profile

4 | 5 |
6 | "> 7 | 8 | 9 |
10 | 11 | <% include _footer %> 12 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/views/index.ejs: -------------------------------------------------------------------------------- 1 | <% include _header %> 2 | 3 |

Welcome to Learn About Me!

4 | 5 | <% users.forEach(function(user) { %> 6 | 7 |
8 | 13 | <% if (user.bio) { %> 14 |
<%= user.bio %>
15 | <% } %> 16 |
17 | 18 | <% }) %> 19 | 20 | <% include _footer %> 21 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/views/login.ejs: -------------------------------------------------------------------------------- 1 | <% include _header %> 2 | 3 |

Log in

4 | 5 |
6 | 7 | 8 | 9 |
10 | 11 | <% include _footer %> 12 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/views/profile.ejs: -------------------------------------------------------------------------------- 1 | <% include _header %> 2 | 3 | <% if ((currentUser) && (currentUser.id === user.id)) { %> 4 | Edit your profile 5 | <% } %> 6 | 7 |

<%= user.name() %>

8 |

Joined on <%= user.createdAt %>

9 | 10 | <% if (user.bio) { %> 11 |

<%= user.bio %>

12 | <% } %> 13 | 14 | <% include _footer %> 15 | -------------------------------------------------------------------------------- /Chapter_08/learn-about-me/views/signup.ejs: -------------------------------------------------------------------------------- 1 | <% include _header %> 2 | 3 |

Sign up

4 | 5 |
6 | 7 | 8 | 9 |
10 | 11 | <% include _footer %> 12 | -------------------------------------------------------------------------------- /Chapter_09/simple_tests/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log 3 | -------------------------------------------------------------------------------- /Chapter_09/simple_tests/capitalize.js: -------------------------------------------------------------------------------- 1 | function capitalize(str) { 2 | var firstLetter = str.charAt(0).toUpperCase(); 3 | var rest = str.slice(1).toLowerCase(); 4 | return firstLetter + rest; 5 | } 6 | 7 | module.exports = capitalize; 8 | -------------------------------------------------------------------------------- /Chapter_09/simple_tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "devDependencies": { 4 | "chai": "^1.9.2", 5 | "mocha": "^2.0.1" 6 | }, 7 | "scripts": { 8 | "test": "mocha" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_09/simple_tests/test/capitalize.js: -------------------------------------------------------------------------------- 1 | var capitalize = require("../capitalize"); 2 | 3 | var chai = require("chai"); 4 | var expect = chai.expect; 5 | 6 | describe("capitalize", function() { 7 | 8 | it("leaves empty strings alone", function() { 9 | expect(capitalize("")).to.equal(""); 10 | }); 11 | 12 | it("leaves strings with no words alone", function() { 13 | expect(capitalize(" ")).to.equal(" "); 14 | expect(capitalize("123")).to.equal("123"); 15 | }); 16 | 17 | it("capitalizes single words", function() { 18 | expect(capitalize("express")).to.equal("Express"); 19 | expect(capitalize("cats")).to.equal("Cats"); 20 | }); 21 | 22 | it("makes the rest of the string lowercase", function() { 23 | expect(capitalize("javaScript")).to.equal("Javascript"); 24 | }); 25 | 26 | it("capitalizes multiple-word strings", function() { 27 | expect(capitalize("what is Express?")).to.equal("What is express?"); 28 | expect(capitalize("i love lamp")).to.equal("I love lamp"); 29 | }); 30 | 31 | it("leaves already-capitalized words alone", function() { 32 | expect(capitalize("Express")).to.equal("Express"); 33 | expect(capitalize("Evan")).to.equal("Evan"); 34 | expect(capitalize("Catman")).to.equal("Catman"); 35 | }); 36 | 37 | it("capitalizes String objects without changing their values", function() { 38 | var str = new String("who is JavaScript?"); 39 | expect(capitalize(str)).to.equal("Who is javascript?"); 40 | expect(str.valueOf()).to.equal("who is JavaScript?"); 41 | }); 42 | 43 | }); 44 | -------------------------------------------------------------------------------- /Chapter_09/simple_tests/test/mocha.opts: -------------------------------------------------------------------------------- 1 | --check-leaks 2 | -------------------------------------------------------------------------------- /Chapter_09/whats_my_useragent/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log 3 | -------------------------------------------------------------------------------- /Chapter_09/whats_my_useragent/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var path = require("path"); 3 | 4 | var app = express(); 5 | 6 | app.set("port", process.env.PORT || 3000); 7 | 8 | var viewsPath = path.join(__dirname, "views"); 9 | app.set("view engine", "ejs"); 10 | app.set("views", viewsPath); 11 | 12 | app.get("/", function(req, res) { 13 | var userAgent = req.headers["user-agent"] || "none"; 14 | 15 | if (req.accepts("html")) { 16 | res.render("index", { userAgent: userAgent }); 17 | } else { 18 | res.type("text"); 19 | res.send(userAgent); 20 | } 21 | }); 22 | 23 | app.listen(app.get("port"), function() { 24 | console.log("App started on port " + app.get("port")); 25 | }); 26 | 27 | module.exports = app; 28 | -------------------------------------------------------------------------------- /Chapter_09/whats_my_useragent/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "whats-my-user-agent", 3 | "private": true, 4 | "scripts": { 5 | "start": "node app", 6 | "test": "mocha" 7 | }, 8 | "dependencies": { 9 | "ejs": "^1.0.0", 10 | "express": "5.0.0-alpha.1" 11 | }, 12 | "devDependencies": { 13 | "cheerio": "^0.17.0", 14 | "mocha": "^2.0.1", 15 | "supertest": "^0.14.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter_09/whats_my_useragent/test/html.js: -------------------------------------------------------------------------------- 1 | var app = require("../app"); 2 | 3 | var supertest = require("supertest"); 4 | var cheerio = require("cheerio"); 5 | 6 | describe("html response", function() { 7 | 8 | var request; 9 | beforeEach(function() { 10 | request = supertest(app) 11 | .get("/") 12 | .set("User-Agent", "a cool browser") 13 | .set("Accept", "text/html"); 14 | }); 15 | 16 | it("returns an HTML response", function(done) { 17 | request 18 | .expect("Content-Type", /html/) 19 | .expect(200) 20 | .end(done); 21 | }); 22 | 23 | it("returns your User Agent", function(done) { 24 | request 25 | .expect(function(res) { 26 | var htmlResponse = res.text; 27 | var $ = cheerio.load(htmlResponse); 28 | var userAgent = $(".user-agent").html().trim(); 29 | if (userAgent !== "a cool browser") { 30 | throw new Error("User Agent not found (found: " + userAgent + ")"); 31 | } 32 | }) 33 | .end(done); 34 | }); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /Chapter_09/whats_my_useragent/test/txt.js: -------------------------------------------------------------------------------- 1 | var app = require("../app"); 2 | 3 | var supertest = require("supertest"); 4 | 5 | describe("plain text response", function() { 6 | 7 | var request; 8 | beforeEach(function() { 9 | request = supertest(app) 10 | .get("/") 11 | .set("User-Agent", "a cool browser") 12 | .set("Accept", "text/plain"); 13 | }); 14 | 15 | it("returns a plain text response", function(done) { 16 | request 17 | .expect("Content-Type", /text\/plain/) 18 | .expect(200) 19 | .end(done); 20 | }); 21 | 22 | it("returns your User Agent", function(done) { 23 | request 24 | .expect(function(res) { 25 | if (res.text !== "a cool browser") { 26 | throw new Error("Response does not contain User Agent"); 27 | } 28 | }) 29 | .end(done); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /Chapter_09/whats_my_useragent/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 15 | 16 | 17 | 18 |

Your User Agent is:

19 |

20 | <%= userAgent %> 21 |

22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Chapter_10/csrf-example/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var session = require("express-session"); 3 | var bodyParser = require("body-parser"); 4 | var csrf = require("csurf"); 5 | 6 | var app = express(); 7 | 8 | app.set("view engine", "ejs"); 9 | 10 | app.use(session({ 11 | secret: "@lHJr+JrSwv1W&J904@W%nmWf++K99pRBvk&wBaNAs4JTid1Ji", 12 | resave: false, 13 | saveUninitialized: true 14 | })); 15 | 16 | app.use(bodyParser.urlencoded({ 17 | extended: false 18 | })); 19 | 20 | app.use(csrf()); 21 | 22 | app.get("/", function(req, res) { 23 | res.render("index", { 24 | csrfToken: req.csrfToken() 25 | }); 26 | }); 27 | 28 | app.post("/submit", function(req, res) { 29 | res.send("Form submission worked!"); 30 | }); 31 | 32 | app.use(function(err, req, res, next) { 33 | if (err.code !== "EBADCSRFTOKEN") { 34 | next(err); 35 | return; 36 | } 37 | res.status(403); 38 | res.send("CSRF error."); 39 | }); 40 | 41 | app.use(function(err, req, res, next) { 42 | res.status(500); 43 | res.send("Non-CSRF error."); 44 | }); 45 | 46 | app.listen(3000, function() { 47 | console.log("App started"); 48 | }); 49 | -------------------------------------------------------------------------------- /Chapter_10/csrf-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "body-parser": "^1.10.2", 8 | "csurf": "^1.6.5", 9 | "ejs": "^2.2.3", 10 | "express": "^4.11.1", 11 | "express-session": "^1.10.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Chapter_10/csrf-example/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CSRF example 7 | 8 | 9 | 10 | 11 |

CSRF form test

12 | 13 |
14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Chapter_10/forever-example/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | 3 | var app = express(); 4 | 5 | app.get("/", function(req, res) { 6 | res.send("Visit /crash to crash the site!"); 7 | }); 8 | 9 | app.get("/crash", function(req, res) { 10 | res.status(500); 11 | res.send("Crashing the site..."); 12 | process.exit(0); 13 | }); 14 | 15 | app.listen(3000, function() { 16 | console.log("App started"); 17 | }); 18 | -------------------------------------------------------------------------------- /Chapter_10/forever-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "forever app.js" 5 | }, 6 | "dependencies": { 7 | "express": "5.0.0-alpha.2", 8 | "forever": "^0.13.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_10/print-queries/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var util = require("util"); 3 | 4 | var app = express(); 5 | 6 | app.set("port", process.env.PORT || 3000); 7 | 8 | app.use(function(req, res) { 9 | res.type("text/plain"); 10 | res.send([ 11 | "req.query looks like this:", 12 | util.inspect(req.query) 13 | ].join("\n\n")); 14 | }); 15 | 16 | app.listen(app.get("port"), function() { 17 | console.log("App started on port " + app.get("port")); 18 | }); 19 | -------------------------------------------------------------------------------- /Chapter_10/print-queries/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app" 5 | }, 6 | "dependencies": { 7 | "express": "5.0.0-alpha.2" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Chapter_11/grunt-examples/.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | -------------------------------------------------------------------------------- /Chapter_11/grunt-examples/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | less: { 4 | main: { 5 | options: { 6 | paths: ["my_css"] 7 | }, 8 | files: { 9 | "tmp/serve/main.css": "my_css/main.less" 10 | } 11 | } 12 | }, 13 | browserify: { 14 | client: { 15 | src: ["my_javascripts/main.js"], 16 | dest: "tmp/serve/main.js" 17 | } 18 | }, 19 | uglify: { 20 | myClient: { 21 | files: { 22 | "tmp/serve/main.min.js": ["tmp/serve/main.js"] 23 | } 24 | } 25 | }, 26 | watch: { 27 | scripts: { 28 | files: ["**/*.js"], 29 | tasks: ["browserify"] 30 | }, 31 | styles: { 32 | files: ["**/*.less"], 33 | tasks: ["less"] 34 | } 35 | } 36 | }); 37 | 38 | grunt.loadNpmTasks("grunt-contrib-less"); 39 | grunt.loadNpmTasks("grunt-browserify"); 40 | grunt.loadNpmTasks("grunt-contrib-uglify"); 41 | grunt.loadNpmTasks("grunt-contrib-watch"); 42 | 43 | grunt.registerTask("default", ["browserify", "less", "uglify"]); 44 | }; 45 | -------------------------------------------------------------------------------- /Chapter_11/grunt-examples/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var path = require("path"); 3 | 4 | var app = express(); 5 | 6 | app.use(express.static(path.resolve(__dirname, "public"))); 7 | app.use(express.static(path.resolve(__dirname, "tmp/serve"))); 8 | 9 | app.listen(3000, function() { 10 | console.log("App started on port 3000."); 11 | }); 12 | -------------------------------------------------------------------------------- /Chapter_11/grunt-examples/my_css/main.less: -------------------------------------------------------------------------------- 1 | article { 2 | display: block; 3 | h1 { 4 | font-size: 16pt; 5 | color: #900; 6 | } 7 | p { 8 | line-height: 1.5em; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Chapter_11/grunt-examples/my_javascripts/main.js: -------------------------------------------------------------------------------- 1 | var randomString = require("random-string"); 2 | 3 | console.log(randomString({ length: 10 })); 4 | -------------------------------------------------------------------------------- /Chapter_11/grunt-examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app", 5 | "grunt": "grunt" 6 | }, 7 | "devDependencies": { 8 | "grunt": "^0.4.5", 9 | "grunt-browserify": "^3.8.0", 10 | "grunt-cli": "^0.1.13", 11 | "grunt-contrib-less": "^1.0.1", 12 | "grunt-contrib-uglify": "^0.9.1", 13 | "grunt-contrib-watch": "^0.6.1" 14 | }, 15 | "dependencies": { 16 | "express": "5.0.0-alpha.2", 17 | "random-string": "^0.1.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Chapter_11/heroku-app/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Chapter_11/heroku-app/Procfile: -------------------------------------------------------------------------------- 1 | web: npm run production 2 | -------------------------------------------------------------------------------- /Chapter_11/heroku-app/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var app = express(); 3 | 4 | app.set("port", process.env.PORT || 3000); 5 | 6 | app.get("/", function(req, res) { 7 | res.send("Hello world!"); 8 | }); 9 | 10 | app.listen(app.get("port"), function() { 11 | console.log("App running on port " + app.get("port")); 12 | }); 13 | -------------------------------------------------------------------------------- /Chapter_11/heroku-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "start": "node app", 5 | "production": "forever app.js" 6 | }, 7 | "dependencies": { 8 | "express": "5.0.0-alpha.2", 9 | "forever": "^0.13.0" 10 | }, 11 | "engines": { 12 | "node": "4.2.x" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 27 | node_modules 28 | 29 | # Debug log from npm 30 | npm-debug.log 31 | -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | 8 | var routes = require('./routes/index'); 9 | var users = require('./routes/users'); 10 | 11 | var app = express(); 12 | 13 | // view engine setup 14 | app.set('views', path.join(__dirname, 'views')); 15 | app.set('view engine', 'jade'); 16 | 17 | // uncomment after placing your favicon in /public 18 | //app.use(favicon(__dirname + '/public/favicon.ico')); 19 | app.use(logger('dev')); 20 | app.use(bodyParser.json()); 21 | app.use(bodyParser.urlencoded({ extended: false })); 22 | app.use(cookieParser()); 23 | app.use(express.static(path.join(__dirname, 'public'))); 24 | 25 | app.use('/', routes); 26 | app.use('/users', users); 27 | 28 | // catch 404 and forward to error handler 29 | app.use(function(req, res, next) { 30 | var err = new Error('Not Found'); 31 | err.status = 404; 32 | next(err); 33 | }); 34 | 35 | // error handlers 36 | 37 | // development error handler 38 | // will print stacktrace 39 | if (app.get('env') === 'development') { 40 | app.use(function(err, req, res, next) { 41 | res.status(err.status || 500); 42 | res.render('error', { 43 | message: err.message, 44 | error: err 45 | }); 46 | }); 47 | } 48 | 49 | // production error handler 50 | // no stacktraces leaked to user 51 | app.use(function(err, req, res, next) { 52 | res.status(err.status || 500); 53 | res.render('error', { 54 | message: err.message, 55 | error: {} 56 | }); 57 | }); 58 | 59 | 60 | module.exports = app; 61 | -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('express-generated-app:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-generated-app", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "~1.12.0", 10 | "cookie-parser": "~1.3.4", 11 | "debug": "~2.1.1", 12 | "express": "~4.12.2", 13 | "jade": "~1.9.2", 14 | "morgan": "~1.5.1", 15 | "serve-favicon": "~2.2.0" 16 | } 17 | } -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET home page. */ 5 | router.get('/', function(req, res, next) { 6 | res.render('index', { title: 'Express' }); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/routes/users.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | /* GET users listing. */ 5 | router.get('/', function(req, res, next) { 6 | res.send('respond with a resource'); 7 | }); 8 | 9 | module.exports = router; 10 | -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /Chapter_12/express-generated-app/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is the code from the book [*Express.js in Action*](https://manning.com/hahn/?a_aid=express-in-action&a_bid=fe3fcff7). 2 | 3 | I've provided a [Vagrant](https://www.vagrantup.com/) virtual machine with Node (installed with [nvm](https://github.com/creationix/nvm)), the Express application generator, and MongoDB. To use it, install Vagrant, and then: 4 | 5 | ```sh 6 | vagrant up # to start the virtual machine 7 | vagrant ssh # to SSH into the virtual machine 8 | cd /vagrant # to get to the code 9 | ``` 10 | 11 | Note that many of the dependencies in this project are out of date, as the book is now several years old. Please upgrade to newer versions if using this code for real! 12 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | $script = <