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.
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 --saveCreate 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.jsInitially 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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
