/angularjs/

Express.js (Node.js), AngularJS and MongoDB

2014-08-22 23:20:54

GitHub

This time we will play with:

In this post, you will learn:

  • how to create AngularJS application and expose this app via node
  • how to create REST API for frontend app
  • and how to use MongoDB

We have to start from frontend and backend dependencies

Frontend dependencies (bower.json)

{
    "name": "EA1",
    "version": "0.0.1",
    "authors": [
        "michał szałkowski btbw.pl"
    ],
    "license": "MIT",
    "dependencies": {
        "jquery": "~2.1.1",
        "angular": "~1.2.22",
        "angular-route": "~1.2.22",
        "bootstrap": "~3.2.0"
    }
}

(.bowerrc)

{
    "directory": "public/vendor"
}

After creating this files please run:

bower install

Backend dependencies (package.json)

{
    "name": "node-api",
    "main": "server.js",
    "dependencies": {
        "express": "~4.0.0",
        "mongoose": "~3.6.13",
        "body-parser": "~1.0.1"
    }
}

After creating this file please run:

npm install

Project structure

Backend - Server

I can put all code in one file, but for readability I divided server code.

Server main file (server.js)

var express = require('express');
var app = express();
var bodyParser = require('body-parser');

require('./server/config/mongoose').initDb();

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

app.use(express.static(__dirname + '/public'));

app.use('/api', require('./server/article/route').init());

app.listen(8080);
console.log('==> goto: http://localhost:' + 8080);

What we have here ? - first of all require('./server/config/mongoose').initDb(), this line of code use mongoose.js file to setup mongodb connection - next we have app.use(express.static(__dirname + '/public'));, thanks to the line our static resource are available in the browser (AngularJS app) - and the last app.use('/api', require('./server/article/route').init());, this line use code from route.js to setup REST API for Article

ArticleSchema (article.js)

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

var ArticleSchema = new Schema({
    name: String,
    desc: String
});

module.exports = mongoose.model('Article', ArticleSchema);

Router Article Api (route.js)

var express = require('express');
var Article = require('./article');

module.exports.init = function () {

    var routerApi = express.Router();

    // middleware to use for all requests
    routerApi.use(function (req, res, next) {
        console.log('Somebody uses our API !');
        next();
    });

    // POST NEW ITEM http://localhost:8080/api/articles
    routerApi.route('/articles').post(function (req, res) {

        var article = new Article();
        article.name = req.body.name;
        article.desc = req.body.desc;

        article.save(function (err) {
            if (err) {
                res.send(err);
            }
            res.json({ message: 'article created!' });
        });

    });

    // GET ALL ITEMS http://localhost:8080/api/articles
    routerApi.route('/articles').get(function (req, res) {
        Article.find(function (err, article) {
            if (err) {
                res.send(err);
            }
            res.json(article);
        });
    });

    // GET ONE ITEM http://localhost:8080/api/bears/:article_id
    routerApi.route('/articles/:article_id').get(function (req, res) {
        Article.findById(req.params.article_id, function (err, article) {
            if (err) {
                res.send(err);
            }
            res.json(article);
        });
    });

    // PUT UPDATE ONE ITEM http://localhost:8080/api/articles/:article_id
    routerApi.route('/articles/:article_id').put(function (req, res) {

        Article.findById(req.params.article_id, function (err, article) {
            if (err) {
                res.send(err);
            }
            article.name = req.body.name;
            article.desc = req.body.desc;

            article.save(function (err) {
                if (err) {
                    res.send(err);
                }
                res.json({ message: 'article updated!' });
            });

        });
    });

    //DELETE ONE ITEM http://localhost:8080/api/articles/:article_id
    routerApi.route('/articles/:article_id').delete(function (req, res) {
        Article.remove({
            _id: req.params.article_id
        }, function (err, article) {
            if (err) {
                res.send(err);
            }

            res.json({ message: 'Successfully deleted' });
        });
    });

    return routerApi;
};

Mongoose configuration (mongoose.js)

module.exports.initDb = function () {

    var mongoose = require('mongoose');

    mongoose.connect('mongodb://localhost/express4test');

    var db = mongoose.connection;

    db.on('error', console.error.bind(console, 'connection error...'));
    db.once('open', function () {
        console.log('express4test db opened');
    });
};

Frontend - AngularJS (app.js)

Frontend script is very simple. In app.js we have route configuration and four controller.

angular.module('exAnApp', ['ngRoute'])

    .config(function ($routeProvider) {
        $routeProvider.
            when('/articles', {templateUrl: 'app/tpl/list.tpl.html', controller: 'ArticlesListCtrl'}).
            when('/article/:id', {templateUrl: 'app/tpl/details.tpl.html', controller: 'ArticleDetailCtrl'}).
            when('/article_new', {templateUrl: 'app/tpl/form.tpl.html', controller: 'ArticleCreateCtrl'}).
            when('/article_remove/:id', {template: 'ok', controller: 'ArticleRemoveCtrl'}).
            otherwise({redirectTo: '/articles'});
    })

    .controller('ArticlesListCtrl', function ($scope, $http) {
        $http.get('/api/articles').
            success(function (data, status, headers, config) {
                $scope.articles = data;
            });
    })

    .controller('ArticleDetailCtrl', function ($scope, $routeParams, $http) {
        $http.get('/api/articles/' + $routeParams.id).
            success(function (data, status, headers, config) {
                $scope.article = data;
            });

        $scope.submit = function () {

            var newArticle = {
                name: $scope.article.name,
                desc: $scope.article.desc
            };

            $http.put('/api/articles/' + $scope.article._id, newArticle).
                success(function (data, status, headers, config) {
                    $scope.message = data.message;
                });
        };
    })

    .controller('ArticleCreateCtrl', function ($scope, $routeParams, $http) {
        $scope.submit = function () {

            var newArticle = {
                name: $scope.name,
                desc: $scope.desc
            };

            $http.post('/api/articles/', newArticle).
                success(function (data, status, headers, config) {
                    $scope.message = data.message;
                });

            $scope.name = "";
            $scope.desc = "";
        };
    })

    .controller('ArticleRemoveCtrl', function ($scope, $routeParams, $http, $location) {
        $http.delete('/api/articles/' + $routeParams.id).
            success(function (data, status, headers, config) {
                //$scope.message = data.message;
                $location.path("/articles");
            });
    })
;