2013-10-22

Todo App

Todo apps are considered to be quintessential in showcasing frameworks akin to famous Todomvc.com for front-end JavaScript frameworks. In this example, we’ll use Jade, forms, LESS, AJAX/XHR and CSRF.

In our Todo app, we’ll intentionally not use Backbone.js or Angular to demonstrate how to build traditional websites with the use of forms and redirects. In addition to that, we’ll explain how to plug-in CSRF and LESS.

Example: All the source code is in the github.com/azat-co/todo-express for your convenience.

Here are some screenshots of Todo app in which we start from a home page:



There’s an empty list (unless you played with this app before):



Now we can add four items to the Todo List:



Mark one of the tasks as “done”, e.g.. “Buy milk”:

Going to the Complete page reveals this done item:

Deletion of an item from the Todo list is the only action performed via AJAX/XHR request. The rest of the logic is done via GETs and POSTs (by forms).

Scaffolding

As usual, we start by running

This will give us the basic Express.js application.

We’ll need to add two extra dependencies to package.json, the less-middleware and Mongoskin libraries:

Changing the name to todo-express is optional:

MongoDB

Install MongoDB if you don’t have it already.

For more flavors of MongoDB installation, check out the official docs.

Structure

The final version of the app has the following folder/file structure (GitHub):

The *.less in bootstrap folder means there are bunch of Twitter Bootstrap (the CSS framework) source files. They’re available at GitHub.

app.js

This is a break down of the Express.js generated app.js file with addition of routes, database, session, LESS and param middlewares.

Firstly, we import dependencies with Node.js global require() function:

Similarly, we get access to our own modules which are app’s routes:

The core http and path modules will be needed as well:

Mongoskin is a better alternative to the native MongoDB driver:

One line is all we need to get the database connection object. The first param follows standard URI convention of protocol://username:password@host:port/database:

The app itself:

In this middleware, we export the database object to all middlewares. By doing so, we’ll be able to perform database operations in the routes modules:

We just store the tasks collection in every request:

This line allows us to access appname from within every jade template:

We set the server port to either the environment variable or if that’s undefined to 3000:

These statements tell Express.js where templates live and what file extension to prepend in case the extension is omitted during the render calls:

Display Express.js favicon (the graphic in the URL address bar of browsers):

Out-of-the-box logger will print requests in the terminal window:

The bodyParser() middleware is needed for painlessly accessing incoming data:

The methodOverride() middleware is a work around for HTTP methods that involve headers. It’s not essential for this example, but we’ll leave it here:

To use CSRF, we need cookieParser() and session():

The csrf() middleware itself. The order is important; in other words, csrf() must be preceded by cookieParser() and session():

To process LESS stylesheets into CSS ones, we utilize less-middleware in this manner:

The other static files are also in the public folder:

Remember CSRF? This is how we expose it to templates:

The router plug-in is enabled by this statement. It’s important to have this line after less-middleware and csrf() lines above:

It’s possible to configure different behavior based on environments:

When there’s a request that matches route/RegExp with :task_id in it, this block is executed:

The value of task ID is in taskId and we query the database to find that object:

It’s very important to check for errors and empty results:

If there’s data, store it in the request and proceed to next middleware:

Now it’s time to define our routes. We start with home page:

The Todo List page:

This route will mark all tasks in the todo list as completed if the user presses all done button. In a RESP API, the HTTP method would be PUT but because we’re building classical web apps with forms, we have to use POST:

The same URL for adding new tasks as for marking all tasks completed, but in the previous methods itself (markAllCompleted) you’ll see how we handle flow control:

To mark a single task completed, we use aforementioned :task_id string in our URL pattern. In REST API, this should have been a PUT request:

Unlike with the POST route above, we utilize Express.js param middleware with :task_id token:

For our Completed page, we define this route:

In case of malicious attacks or mistyped URLs, it’s a user-friendly thing to catch all requests with *. Keep in mind that if we had a match previously, the Node.js won’t come to execute this block:

Finally, we spin up our application with good ’ol http method:

The full content of app.js file:

Routes

There are only two files in routes folder. One of them serves the home page (e.g., http://localhost:3000/) and is straightforward:

The remaining logic that deals with tasks itself has been placed in the todo-express/routes/tasks.js. Let’s break it down a bit.

We start by exporting list() request handler that gives us list of incomplete tasks:

To do so, we perform a database search with completed=false query:

In the callback, we need to check for any errors:

Since we use toArray(), we can send the date directly to the template:

Adding a new task requires us to check for the name parameter:

Thanks to our middleware, we already have a database collection in the req object, and the default value for the task is incomplete (completed: false):

Again, it’s important to check for errors and propagate them with Express.js next() function:

The logging is optional; however, it’s useful for learning and debugging:

Lastly, we redirect back to the Todo List page when the saving operation is finished successfully:

This method marks all incomplete tasks as complete:

Because we had to re-use POST route and since it’s a good illustration of flow control, we check for the all_done parameter to decide if this request comes from the all done button or the add button:

If the execution come this far, we perform db query with multi: true:

Significant error handling, logging and redirection back to Todo List page:

The Completed route is akin to Todo List except for the completed flag value (true in this case):

This is the route that takes care of marking a single task as done. We use updateById but the same thing can be accomplished with a plain update method from Mongoskin/MongoDB API. The trick with completed: req.body.completed === 'true is needed because the incoming value is a string and not a boolean.

Once more, we perform error and results check (update() and updateById() don’t return object, but the count of affected documents instead):

Delete is the single route called by an AJAX request. However, there’s nothing special about its implementation. The only difference is that we don’t redirect, but send status 200 back.

Just for your information, the remove() method can be used instead of removeById().

For your convenience, here’s the full content of the todo-express/routes/tasks.js file:

Jades

In the Todo app, we use four templates:

layout.jade: the skeleton of HTML pages that is used on all pages

index.jade: home page

tasks.jade: Todo List page

tasks_completed.jade: Completed page

Let’s go through each file starting with layout.jade. It starts with doctype, html and head types:

We should have appname variable set:

Next we include *.css files but underneath, Express.js will serve its contents from LESS files:

The body with Twitter Bootstrap structure consist of .container and .navbar. To read more about those and other classes, go to getbootstrap.com/css/:

This is the place where other jades (like tasks.jade) will be imported:

The last lines include front-end JavaScript files:

The full layout.jade file:

The index.jade file is our home page and it’s quite vanilla. The most interesting thing it had is the nav-pills menu:

The tasks.jade uses extends layout:

Then goes our main page specific content:

The div with list class will hold the Todo List:

The form to mark all items as done has CSRF token in a hidden field and uses POST method pointed to /tasks:

Similar CSRF enabled form is for new task creation:

When we start the app for the first time (or clean the database), there are no tasks:

Jade supports iterations with each command:

This form submits data to individual task route:

The index variable is used to display order in the list of tasks:

The delete button doesn’t have anything fancy attached to it, because events are attached to these buttons from main.js front-end JavaScript file:

The full source code of tasks.jade:

Last but not least, comes tasks_completed.jade which is just a striped down version of tasks.jade file:

LESS

As we’ve mentioned before, after applying proper middleware in app.js files, we can put *.less files anywhere under public folder. Express.js works by accepting request for some .css file and tries to match corresponding file by name. Therefore, we include *.css files in our jades.

Here is the content of the todo-express/public/stylesheets/main.less file:

Conclusion

The Todo app is considered classical because it doesn’t rely on any front-end framework. This was done intentionally to show how easy it is to use Express.js for such tasks. In modern day development, people often leverage some sort of REST API server architecture with front-end client built with Backbone.js, Angular, Ember or something else. Next examples dive into details about how to write such servers.

If you found this tutorial helpful, please take a look at Express.js Guide book, in which there many similar examples of Node.js developement.

Show more