Permalink
Browse files

basic working example

  • Loading branch information...
1 parent b87c3b5 commit 64751c7c6263e8f3aeb3cf5f483d7f39cf1622fd @PuerkitoBio committed Mar 23, 2012
Showing with 184 additions and 1 deletion.
  1. +39 −1 README.md
  2. +15 −0 app.js
  3. +46 −0 lib/config.js
  4. +21 −0 lib/db/index.js
  5. +16 −0 lib/db/model.js
  6. +13 −0 lib/handler/index.js
  7. +7 −0 lib/router/index.js
  8. +8 −0 lib/server.js
  9. +2 −0 package.json
  10. +6 −0 public/css/style.css
  11. +1 −0 public/js/bootstrap.js
  12. +1 −0 test/handler.test.js
  13. +9 −0 views/index.jade
View
40 README.md
@@ -1,5 +1,43 @@
# Express boilerplate #
-This project started out as a [blog post about how to structure a Web Application using node.js and Express][post] (in French). It is intended as an example of the suggested structure in the article.
+This project started out as a [blog post about how to structure a Web Application using node.js and Express][post] (in French). It is intended as a working example of the suggested structure in the article.
+
+## Installing
+
+Obviously you need node.js and npm. `git clone` the repository, then run `npm install -d` in the root directory to setup the dependencies. Once installed, you can run the super exciting app with `make` or `npm start` and browse to `http://localhost:3000/`. When I add some sample unit tests, you'll be able to run them using `make test` or `npm test`.
+
+## Structure
+
+ express-boilerplate
+ lib [community convention for server-side code]
+ db [or "models" if preferred, manages connection to DB and exposes models]
+ handler [application logic, actual implementation of the routes]
+ router [routes definition]
+ config [server configuration, could be a directory with multiple files in a more complex project]
+ server [creates and initializes the HTTP server]
+ public [unrestricted area]
+ css [stylesheets, could be plain CSS or preprocessor source files]
+ img [images and icons for the web app]
+ js [client-side javascript files]
+ test [community convention for automated unit test files]
+ views [templates for rendering of HTML pages, could be any Express-supported engine, Jade in this example]
+ Makefile [use "make" to run, "make test" to test, options available, see source]
+ app.js [dumb - no app logic - master file to assemble dependencies and start the app]
+
+## Dependency injection
+
+This initial version uses a very basic dependency injection pattern (arguments to the function exposed with `module.exports` in the target module). Other ways will be discussed in a future article on [my blog][blog].
+
+## Use of "debug"
+
+I use the tiny [debug][] library instead of logging info to the console just to keep an eye on what's going on and some quick debugging. The nice thing about this library is the ease of use, the conditional output using the DEBUG environment variable, and the colors in the terminal. I like it. Easy to take out if you don't. See for yourself:
+
+![](http://dl.dropbox.com/u/21605004/DebugWithColors.png)
+
+## What's with "db" ?
+
+`/lib/db` could well be named `/lib/models` if you prefer. That's what it's for, the models in your Web app. Since I often use MongoDB, I go with the "db" directory. It's not actually used in this boilerplate example, but the code is there to show how I usually organize it.
[post]: http://hypermegatop.calepin.co/structurer-une-application-web-avec-express-et-nodejs.html
+[debug]: https://github.com/visionmedia/debug
+[blog]: http://hypermegatop.calepin.co/
View
15 app.js
@@ -0,0 +1,15 @@
+var debug = require('debug')('app'),
+ server = require('./lib/server'),
+ // "db" would be required here, and usually injected into "handler"
+ // db = require('./lib/db'),
+ handler = require('./lib/handler');
+
+// Configure the server
+require('./lib/config')(__dirname, server);
+
+// Setup routes
+require('./lib/router')(server, handler);
+
+// All set, start listening!
+server.listen(3000);
+debug("Express server listening on port %d in %s mode", server.address().port, process.env.NODE_ENV);
View
46 lib/config.js
@@ -0,0 +1,46 @@
+var debug = require('debug')('config'),
+ express = require('express');
+
+// One argument (the root directory of the app), and a dependency, an Express HTTP server to configure
+module.exports = function (rootDir, server) {
+ server.configure(function () {
+ debug('Generic configuration...');
+
+ // Configure jade as template engine
+ server.set('views', rootDir + '/views');
+ server.set('view engine', 'jade');
+ server.set("view options", {layout: false});
+
+ // Parse the body
+ server.use(express.bodyParser());
+
+ // Use the method override so that PUT and DELETE can be simulated with a POST
+ server.use(express.methodOverride());
+
+ // Parse the cookies
+ server.use(express.cookieParser());
+
+ // Session support, in normal use, put secret in environment var:
+ // server.use(express.session({ secret: process.env.MY_SESSION_SECRET }));
+ server.use(express.session({ secret: 'hypermegatop really!' }));
+
+ // Enable the router
+ server.use(server.router);
+
+ // Serve static content from "public" directory
+ server.use(express.static(rootDir + '/public'));
+ });
+
+ server.configure('dev', function () {
+ debug('"dev" configuration...');
+
+ server.use(express.logger('tiny'));
+ server.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
+ });
+
+ server.configure('production', function () {
+ debug('"production" configuration...');
+
+ server.use(express.errorHandler());
+ });
+};
View
21 lib/db/index.js
@@ -0,0 +1,21 @@
+var debug = require('debug')('db'),
+ mongoose = require('mongoose'),
+ model = require('./model'),
+ connString = 'mongodb://' + process.env.MY_USER + ':' +
+ process.env.MY_PWD + '@somehost.com:9999/DbName';
+
+// This is not actually used in the boilerplate, but is an example of a MongoDB / mongoose setup
+mongoose.connect(connString);
+
+// Should you need to do something on open or close...
+/*
+mongoose.connection.on('open', function () {
+ debug('Mongo connected.');
+});
+
+mongoose.connection.on('close', function () {
+ debug('Mongo closed.');
+});
+*/
+
+module.exports.MyModel = model;
View
16 lib/db/model.js
@@ -0,0 +1,16 @@
+var mongoose = require('mongoose'),
+ Schema = mongoose.Schema;
+
+var ModelSchema = new Schema({
+ someStringData: {type: String, required: true, index: true},
+ someDateData: {type: Date},
+ somePositiveNumberData: {type: Number, min: 0}
+});
+
+// Define some "static" or "instance" methods
+ModelSchema.statics.getAll = function (cb) {
+ this.find({}, cb);
+};
+
+// Export the model
+module.exports = mongoose.model('Model', ModelSchema);
View
13 lib/handler/index.js
@@ -0,0 +1,13 @@
+var debug = require('debug')('handler');
+
+// Self-invoking function, would usually expect "db" as an injected dependency, though not
+// for this simple example.
+module.exports = (function () {
+ debug('setup handlers...');
+
+ return {
+ renderIndex: function (req, res) {
+ res.render('index', {title: "Express Boilerplate"});
+ }
+ };
+}());
View
7 lib/router/index.js
@@ -0,0 +1,7 @@
+var debug = require('debug')('router');
+
+// Two dependencies, an Express HTTP server and a handler
+module.exports = function (server, handler) {
+ debug('setup routes...');
+ server.get('/', handler.renderIndex);
+};
View
8 lib/server.js
@@ -0,0 +1,8 @@
+var debug = require('debug')('server'),
+ express = require('express');
+
+// Self-invoking function, usually not much to do here
+module.exports = (function () {
+ debug('creating Express server...');
+ return express.createServer();
+}());
View
2 package.json
@@ -2,11 +2,13 @@
"name": "express-boilerplate"
, "description": "Example of a suggested structure for a Web application using Express."
, "version": "0.1.0"
+ , "private": true
, "author": "Martin Angers"
, "dependencies": {
"debug": "0.5.x"
, "express": "2.5.x"
, "jade": "0.20.x"
+ , "mongoose": "2.5.x"
}
, "devDependencies": {
"mocha": "0.14.x"
View
6 public/css/style.css
@@ -0,0 +1,6 @@
+/*
+ Just an example, could be an Express-supported stylesheet preprocessor source file (LESS, Stylus, etc.)
+*/
+body {
+ font-family: Arial, "MS Trebuchet", sans-serif;
+}
View
1 public/js/bootstrap.js
@@ -0,0 +1 @@
+// Client-side bootstrap code, to setup a Backbone cilent app, for example. Out of scope for this Express boilerplate.
View
1 test/handler.test.js
@@ -0,0 +1 @@
+// TODO : Add a unit test example...
View
9 views/index.jade
@@ -0,0 +1,9 @@
+!!!
+html
+ title= title
+ link(rel="stylesheet", href="/css/style.css")
+ script(src="/js/bootstrap.js")
+ body
+ h1 Welcome to #{title}
+ p This is me:
+ img(src="/img/me.jpg", alt="PuerkitoBio")

0 comments on commit 64751c7

Please sign in to comment.