Structuring an Express MVC API – Part 2

Summary

In the first post we learned a bit about the MVC pattern itself. Now that we have the pattern down lets see how we can structure our application to follow this pattern. Keep in mind there are many ways to structure an MVC application and this is just one way. Also, since our application is relatively simple we will be organizing it by type instead of by feature. In larger projects organizing your files by feature is nice alternative to use, but for simple project it can be overkill.

However, the most important thing to remember is that whatever structure you choose to follow you stick to it consistently.

Application Structure

The application structure is best introduced from the below image:

todo-list-app-structure
todo-list-app-structure

As you can see the application is nicely laid out into two main folders under the src directory (client and server). Below I will discuss the purpose of each one of the server folders so that you will have a good understanding of how this all fits together.

Server

The server directory is pretty self explanatory. It’s the home to all server side code and it contains the main server side entry point, server.js. This file is very small and it’s purpose is to simply serve as the entry point for our application.

server.js:

process.env.NODE_ENV = process.env.NODE_ENV || 'development';

var express = require('./config/express');
var mongoose = require('./config/mongoose');

var db = mongoose();
var app = express();
app.listen('3000');

module.exports = app;
console.log('Server started on port http://localhost:3000');

List of folders under the server directory:
Config
Controllers
Models
Routes
Views

Config

This directory is home to all of the application configuration stuff. Two main configuration items that I like to have in this directory are:

  • express.js
  • mongoose.js

The express.js file contains all of the express configuration code.

Here is a snippet from express.js.

var express = require('express');
var morgan = require('morgan');
var compress = require('compression');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');

module.exports = function () {
var app = express();

if (process.env.NODE_ENV === 'development') {
    // log all requests
    app.use(morgan('dev'));
} else {
    app.use(compress());
}

app.use(bodyParser.urlencoded(
{
    extended: true
}));
app.use(bodyParser.json());

// support for PUT and DELETE verbs
app.use(methodOverride());

app.set('views', './src/server/views');
app.set('view engine', 'ejs');

require('../routes/index.route.js')(app);
require('../routes/todo.route.js')(app);

As you can see we register all the express middleware and initialize each of our routes from this file.

Mongoose.js

There are two responsibilities of this file:

  • Connect to MongoDB
  • Initialize our Model objects

Here is the file in it’s entirety.

var config = require('./config');
var mongoose = require('mongoose');

module.exports = function () {
var db = mongoose.connect(config.db);

// load models here
require('../models/todo.model');

return db;
};
Env

The env directory is where the server configuration will live. At this time we currently have a development and production file which are loaded based upon the process.evn.NODE_ENV variable. As you can see from the config.js we are concatenating the node environment with the require path so that when we require(config) we will have the correct config settings for our currently running environment.

module.exports = require('./env/' + process.env.NODE_ENV + '.js');

Having an environment specific config is a best practice and will help out when deploying our application to a production server.

Controllers

As I mentioned in the summary section our application structure is organized by type so as you have probably figured out the controllers directory contains all of the controllers. Currently our ToDo application has two controllers: index.controller.js and todo.controller.js. The naming convention that I like use is to add the word controller to the file so that I can re-use both index and todo in other file names but still be able to use IDE navigation shortcuts to clearly see which files I’m navigating.

Models

You can probably guess where this is going by now, but models does just what is says. All models are defined and stored in this directory.

ToDo Model Example:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var ToDoSchema = new Schema({
    description: {type: String},
    dueDate: {
        type: Date,
        default: Date.now
    },
    isComplete: {type: Boolean, default: false}
});

mongoose.model('Todo', ToDoSchema);

In another post I will dive a lot deeper into mongoose which is what we are using to create our Model objects.

Routes

Routes are the core of any API and one of the conventions that I typically use is to begin each route with /api. The reason that I do this to easily distinguish the difference between api and non api routes.

In our MVC API we don’t have any logic in the routing files. Instead the routes are in charge of simply delegating to the correct controller functions.

todo.route.js

var controller = require('../controllers/todo.controller.js');

module.exports = function (app) {
    app.route('/api/todos')
        .post(controller.create)
        .get(controller.list);

    app.route('/api/todos/:id')
        .get(controller.read)
        .put(controller.update)
        .delete(controller.delete);

    app.param('id',controller.todoById);
};

As you can see on the final line we are calling app.param which will run before any of the other middleware so that by the time our routing code gets ran the :id has already been parsed from the request path and added to the request object as req.todo Once that is complete, all the /api/todos/:id routes will have the req.todo object available.

Here is the magic behind the controller.todoById function:

exports.todoById = function (req, res, next, id) {
    Todo.findOne({_id: id}, function (err, todo) {
        if (err) {
            return next(err);
        } else {
            req.todo = todo;
            next();
        }
    })
};

In the above snippet we are simply using the Mongoose findOne function to find our Todo by _id from mongo. Once successfully found we add the object to the req object and call the next middleware (which happens to be all the routes that require the :id.

Views

The final directory that we have is the views directory and as you can guess this is where the view code will live. What view code you might ask? Well, even in our simple API app we still have one static view for the main index page and this is where that file is held.

index.ejs

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Todo It!</title>
</head>
<body>
    <h1>It's already <%= now %> better get something done! </h1>
    <div class="todo-container">
        <form>
            <input type="text" placeholder="What should I get done?"/>
            <input type="submit"/>
        </form>
    </div>
</body>
</html>

In the above code may have noticed the <%= now %>. This is simply the syntax required from our server side view engine EJS.

Final thoughts

This two part series had quite a bit of content that wasn’t covered in too much depth because topics like MongoDB, Mongoose, Express Routing, EJS, etc… could all be several posts in themselves. Hopefully this still gave you an idea for how to structure a simple Express API using MVC.

Last but not least, we didn’t even give AngularJS love with this post, but rest assured we will be getting into a lot of Angular with future posts.

Structuring an Express MVC API – Part 1

Summary

You may be thinking “Huh? MVC for an API?” Well yes, we are discussing MVC for an API. This is part one of a mini-series of posts discussing how to setup a simple Express API using the MVC pattern. In this part I will be giving you a brief introduction into the MVC pattern itself as well as a sneak peak at some of the code in the Todo sample app.

Why learn about this?

You see even though you are creating a RESTful API it is still very important to have a well thought out structure for your application. In today’s post I will discuss an excellent way of separating your Express code so that it is nicely organized and easy to extend.

All code from this post is located on my GitHub page.

What is MVC?

As you may have guessed an MVC application consists of three fundamental parts:
– Model
– View
– Controller

The pattern itself is very common and can be applied at both the project level as well as the sub-project level. For example the front-end of a MEAN application is written in AngularJS and AngularJS lends itself to using an MVC pattern just in the client tier alone. Then, when you implement the back-end you also implement this pattern as I will show you.

Models

Models simply represent the data. An example of a model would be any POJO (Plain Old JavaScript Object). Let’s say that we are creating a ToDo application (Nice! We are creating a Todo App). In our application the Model would be a simple Todo object. Since this is a MEAN blog our model is stored in MongoDB then retrieved via Mongoose. Both Mongoose and Mongo will be discussed in future posts.

Here is an example of a Model from our Todo application.

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var ToDoSchema = new Schema({
    description: String,
    dueDate: {
        type: Date,
        default: Date.now
    },
    isComplete: {type: Boolean, default: false}
});

mongoose.model('Todo', ToDoSchema);

Views

As I mention we are building an Express API so in this case the view is simply the HTTP response received from our API. Although since we are creating a Todo application we will also have plain html views as well.

So there you have it. The View in MVC conceptually represents the display of our data whether that is HTML, JSON, or something else.

Here is the JSON view of a Todo:

{
    "__v": 0,
    "description": "Write blog post",
    "_id": "54c269e6f08121ff125cae74",
    "isComplete": false,
    "dueDate": "2015-01-23T15:33:58.078Z"
}

You can disregard the _id and the __v since these will be discussed in an upcoming MongoDb post.

Controllers

Controllers are the core of the MVC pattern. You can think of them as the glue between the Model and the View. This is the only layer which has knowledge of the other two layers.

The main purpose of the Controller is to retrieve data from the Model and hand it back over to the View. Additionally if there is any logic that needs to be applied this is the place to do that as well.

Here is a quick snippet of a Controller using Mongoose to retrieve the document data.

var Todo = require('mongoose').model('Todo');
exports.create = function (req, res, next) {
    var todo = new Todo(req.body);
    todo.save(function (err) {
        if(err){
            return next(err);
        } else{
            res.json(todo);
        }
    })
};

exports.list = function (req, res, next) {
    Todo.find({}, function (err, todos) {
        if (err) {
            return next(err);
        } else {
            res.json(todos);
        }
    });
};

In the above example the Model is represented by the Todo mongoose object and the view is represented by the JSON sent in the response object.

Up Next

In the next post we will dig into how you can start organizing your application to utilize this pattern.