Build a Test‑Driven REST API with Node, Express & MongoDB

This tutorial walks through creating a simple REST API with POST, GET, PUT, and DELETE endpoints using Node.js, Express, MongoDB, and Mocha, demonstrating a test‑driven development workflow from writing tests to implementing passing code.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Build a Test‑Driven REST API with Node, Express & MongoDB

Tutorial Overview

Using test‑driven development, we build a simple REST API with POST, GET, PUT, and DELETE operations.

First write tests for each endpoint, then implement the code iteratively.

Testing framework: Mocha; web framework: Express 4; database: MongoDB.

Preparation

Install Node.js, MongoDB, and configure the npm mirror. Example tools: nvm for Node, MongoDB Docker image, cnpm mirror, and supervisor for auto‑reloading.

Project Setup

Create a directory test-rest-api and enter it.

Install dependencies

npm install mocha --save-dev
npm install expect.js --save-dev 
npm install superagent --save-dev
npm install express --save
npm install mongo --save
npm install mongoskin --save
npm install body-parser --save

Create source files

express.js – API implementation

express.test.js – test suite

Write Tests

File express.test.js contains tests for POST, GET by ID, GET collection, PUT update, and DELETE.

var superagent = require('superagent')
var expect = require('expect.js')
var mongoskin = require('mongoskin')
var db = mongoskin.db('mongodb://@localhost:27017/test-rest', { safe: true })

describe('express rest api server', function() {
    // clear database before tests
    before(function() {
        db.collection('test').remove({})
    });

    var id;

    // --- test post
    it('post object', function(done) {
        superagent.post('http://localhost:3000/collections/test')
            .send({ name: 'Johns', email: '[email protected]' })
            .end(function(e, res) {
                expect(e).to.eql(null)
                expect(res.body.ops.length).to.eql(1)
                expect(res.body.ops[0]._id.length).to.eql(24)
                id = res.body.ops[0]._id
                done()
            })
    })

    // --- test get by ID
    it('retrieves an object', function(done) {
        superagent.get('http://localhost:3000/collections/test/' + id)
            .end(function(e, res) {
                expect(e).to.eql(null)
                expect(typeof res.body).to.eql('object')
                expect(res.body._id.length).to.eql(24)
                expect(res.body._id).to.eql(id)
                done()
            })
    })

    // --- test get collection
    it('retrieves a collection', function(done) {
        superagent.get('http://localhost:3000/collections/test')
            .end(function(e, res) {
                expect(e).to.eql(null)
                expect(res.body.length).to.be.above(0)
                expect(res.body.map(function(item) { return item._id })).to.contain(id)
                done()
            })
    })

    // --- test update
    it('updates an object', function(done) {
        superagent.put('http://localhost:3000/collections/test/' + id)
            .send({ name: 'Peter', email: '[email protected]' })
            .end(function(e, res) {
                expect(e).to.eql(null)
                done()
            })
    })

    // --- verify updated data
    it('checks an updated object', function(done) {
        superagent.get('http://localhost:3000/collections/test/' + id)
            .end(function(e, res) {
                expect(e).to.eql(null)
                expect(typeof res.body).to.eql('object')
                expect(res.body._id.length).to.eql(24)
                expect(res.body._id).to.eql(id)
                expect(res.body.name).to.eql('Peter')
                done()
            })
    })

    // --- test delete
    it('removes an object', function(done) {
        superagent.del('http://localhost:3000/collections/test/' + id)
            .end(function(e, res) {
                expect(e).to.eql(null)
                expect(res.body.msg).to.eql('success')
                done()
            })
    })
})

Run tests

./node_modules/mocha/bin/mocha express.test.js

Initially all tests fail because the API has not been implemented yet.

Implement API

File express.js starts with basic setup, connects to MongoDB, and defines a root route.

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

var app = express();
app.use(bodyParser());

var db = mongoskin.db('mongodb://@localhost:27017/test-rest', {safe:true});

app.param('collectionName', function(req, res, next, collectionName){
    req.collection = db.collection(collectionName);
    return next();
});

app.get('/', function(req, res) {
    res.send('欢迎');
});

// --- feature code added later

app.listen(3000);

Run with node express.js or supervisor express.js for automatic reload.

Add POST endpoint

app.post('/collections/:collectionName', function(req, res, next) {
    req.collection.insert(req.body, {}, function(e, results){
        if (e) return next(e);
        res.send(results);
    });
});

Run tests again; the POST test now passes.

Add GET by ID

app.get('/collections/:collectionName/:id', function(req, res, next) {
    req.collection.findById(req.params.id, function(e, result){
        if (e) return next(e);
        res.send(result);
    });
});

Run tests; GET by ID passes.

Add GET collection

app.get('/collections/:collectionName', function(req, res, next) {
    req.collection.find({}, {limit:10, sort:[['_id',-1]]}).toArray(function(e, results){
        if (e) return next(e);
        res.send(results);
    });
});

Run tests; collection GET passes.

Add PUT update

app.put('/collections/:collectionName/:id', function(req, res, next) {
    req.collection.updateById(req.params.id, {$set:req.body}, function(e, result){
        if (e) return next(e);
        res.send(result);
    });
});

Run tests; update passes.

Add DELETE

app.del('/collections/:collectionName/:id', function(req, res, next) {
    req.collection.removeById(req.params.id, function(e, result){
        if (e) return next(e);
        res.send((result===1)?{msg:'success'}:{msg:'error'});
    });
});

Run final tests; all six tests pass and the API is complete.

Conclusion

This example demonstrates how to develop a Node.js/Express REST service using a test‑driven approach.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Node.jsREST APIMongoDBExpresstest‑driven developmentmocha
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.