Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
node_modules/
node_modules/*
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
Ninja Store
===========

**NOTE**: Requires Express 3.x / Not compatible with Express 4.x
~~**NOTE**: Requires Express 3.x / Not compatible with Express 4.x~~
**NOTE**: NOW (v0.0.2) compatible with Express 4.x

-----------
Ninja Store is a very simple Express.js app for you to hack around and uderstand Express better.

It is a good project to start learnig Express because if covers GET and POST requests, the Jade template engine, the Stylus CSS engine, login-logout, and sessions. All of it while being a tiny project.

-----------
My book, **Express Web Application Development** is available now - [http://expressjs-book.com/](http://expressjs-book.com/)


To run it use `$ DEBUG=ninja-store:* npm start` or if you installed [nodemon](http://nodemon.io/) (via `npm install -g nodemon`) use `$ nodemon app`
131 changes: 88 additions & 43 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,43 +1,88 @@
var express = require('express')
, http = require('http')
, path = require('path');

var store = store = require('./routes/store');
var app = express();

app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
app.use(express.errorHandler());
});

app.get('/', store.home);
app.post('/', store.home_post_handler);
// display the list of item
app.get('/items', store.items);
// show individual item
app.get('/item/:id', store.item);
// show general pages
app.get('/page', store.page);
app.get('/logout', function(req, res) {
// delete the session variable
delete req.session.username;
// redirect user to homepage
res.redirect('/');
});
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require ('express-session');
var store = require('./routes/store');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
/*
Failure to set "saveUninitialized" and "resave" will generate two warnings:
express-session deprecated undefined resave option; provide resave option app.js:7:9
express-session deprecated undefined saveUninitialized option; provide saveUninitialized option app.js:7:9
This is simply saying the default values will change so they want to ensure that by setting the values
explicitly now. By doing this you won't run into unexpected behavior if the defaults do change in the
near future.
*/
app.use(session({
secret: 'qwertzuiopasdfghjklyxcvbnm',
cookie: { maxAge: 100000 },
saveUninitialized: true, // (default: true)
resave: true, // (default: true)
}));

// GET and POST for root Page
app.get('/', store.home);
app.post('/', store.home_post_handler);
// display the list of item
app.get('/items', store.items);
// show individual item
app.get('/item/:id', store.item);
// show general pages
app.get('/page', store.page);
// logout link
app.get('/logout', function(req, res) {
// delete the session variable
delete req.session.username;
// redirect user to homepage
res.redirect('/');
});

// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});


module.exports = app;
90 changes: 90 additions & 0 deletions bin/www
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

var app = require('../app');
var debug = require('debug')('ninja-store:server');
var http = require('http');

/**
* Get port from environment and store in Express.
*/

var port = normalizePort(process.env.PORT || '4000');
app.set('port', port);

/**
* Create HTTP server.
*/

var server = http.createServer(app);

/**
* Listen on provided port, on all network interfaces.
*/

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
* Normalize a port into a number, string, or false.
*/

function normalizePort(val) {
var port = parseInt(val, 10);

if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
}

/**
* Event listener for HTTP server "error" event.
*/

function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}

/**
* Event listener for HTTP server "listening" event.
*/

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
30 changes: 18 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
{
"name": "application-name",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app"
},
"dependencies": {
"express": "3.1.0",
"jade": "*",
"stylus": "*"
}
{
"name": "ninja-store",
"version": "0.0.2",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.13.2",
"cookie-parser": "~1.3.5",
"debug": "~2.2.0",
"express": "~4.13.1",
"express-session": "^1.13.0",
"jade": "~1.11.0",
"morgan": "~1.6.1",
"serve-favicon": "~2.3.0",
"stylus": "0.42.3"
}
}
7 changes: 2 additions & 5 deletions public/stylesheets/style.css
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
body {
padding: 50px;
padding: 0;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
background: #ccc;
}
a {
color: #0069ff;
}
#container {
#wrapper {
width: 450px;
margin: 0 auto;
padding: 40px 20px;
background: #fff;
box-shadow: 1px 3px 3px #333;
border-radius: 5px;
}
#logo {
text-align: center;
Expand Down
4 changes: 2 additions & 2 deletions public/stylesheets/style.styl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
body
body
padding: 0
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif

Expand All @@ -18,4 +18,4 @@ a
margin: 20px 0 50px

#userbar
margin-bottom: 10px
margin-bottom: 10px
Loading