NodeJS 8 from scratch — Part 6.2 — Api Development
In previous parts, we discussed about —
- basics of nodeJS
- debugging
- asynchronous programming
- call stack and event loop
- promises
- express and deployment
- testing with mocha and supertest
Part 1 — https://medium.com/@anujbaranwal/nodejs-8-from-scratch-part-1-a3c1431f1e15
Part 2 — https://medium.com/@anujbaranwal/nodejs-8-from-scratch-part-2-3035f8f46b09
Part 3 — https://medium.com/@anujbaranwal/nodejs-from-scratch-part-3-20956ec252a3
Part 4 — https://medium.com/@anujbaranwal/nodejs-from-scratch-part-4-d0aadf019c79
Part 5 — https://medium.com/@anujbaranwal/nodejs-8-from-scratch-part-5-3d3e3a84b64
Part 6.1 — https://medium.com/@anujbaranwal/nodejs-8-from-scratch-part-6-1-api-development-5dee11785d62
Repo — https://github.com/anuj070894/nodejs_medium_2
In the previous part of api development(6.1), we learned how to write basic crud operations with a npm module called “mongodb”. In this part and next part, we will learn how to use mongoose with nodeJS with make apis for production.
So, let’s get started
Mongoose ORM(Object Relational Mapping)
A nice way to structure your data from mongoDB in nodeJS
Setting up Mongoose
To set up mongoose, we need to install it —
Run npm install --save mongoose
in server/server.js
const mongoose = require('mongoose');mongoose.Promise = global.Promise; // We are telling the mongoose that we are using the global promisemongoose.connect('mongodb://localhost:27017/TodoApp').then(() => {console.log('Connected to database successfully...');}, (e) => {console.log('Error connecting to database...', e);});const Todo = mongoose.model('Todo', { // we will be creating a model for everything that we want to storetext: {type: String},completed: {type: Boolean},completedAt: {type: Number}}); // the object will describe the properties that we want to storeconst todo = new Todo({text: "Eat lunch",completed: false});
// the below statement will work though it not inside the then success callback of then inside connect because the mongoose buffers it and calls it only once all the setup is goodtodo.save() // responsible for actually saving the data to the database.then((result) => {if (!result) {return console.log('Unable to save the record');}console.log(result);}).catch((e) => {console.log('Some error occurred');});// another model - Userconst User = mongoose.model('User', new mongoose.Schema({name: {type: String}}));const user = new User({name: "Anuj"});user.save().then((result) => {if (!result) {return console.log('Unable to save the record');}console.log(result);}).catch((e) => {console.log('Some error occurred');});
Before we dive any further in creating the apis, we need to learn something about validators types and defaults in model
Validators are used to apply on records to prevent user from saving empty records, invalid emails, etc. http://mongoosejs.com/docs/validation.html has the list of validators in mongoose.
We can put validation on our Todo
model.
var Todo = mongoose.model('Todo', { // collection name: todos
text: {
type: String,
required: true, // meaning that the attribute should be there. ValidationError
minlength: 1,
trim: true // removes any leading and trailing white spaces. trims it first, then validates it next
},
completed: {
type: Boolean,
default: false
},
completedAt: {
type: Number,
default: null
}
}); // this object will describe the various properties for our model
Type casting by mongoose —
const todo = new Todo({text: 5,completed: false});
If we save the record above, it will be saved successfully because mongoose do some type casting internally. Therefore, we should be careful about such data being inserted into the database.
Branch — 03_Init
Postman
Postman is an excellent tool for developers to build modern applications for the apis will be required
The tool can be downloaded from https://www.getpostman.com/ as chrome app (or) standalone application on mac
chrome://apps — once installed, it can be launched from here
Now, that we are aware of the basics of CRUD operations and postman tool to verify our apis, we will start building a real world todo
express app in nodeJS
First, we will separate our code to make it more clear.
Branch — 04_Init
in server/db/mongoose.js
Logic to connect to mongoDB export the mongoose
in server/models/todo.js
Logic to create the todo model and export the todo
in server/models/user.js
Logic to create the user model and export the user
Install express, body-parser
by running — npm install --save express
in server/server.js
Logic to import the models, mongoose, configuring the middlewares and starting the server
To know all the possible statuses, one can look at it from — https://httpstatuses.com/
Branch — 04_Init
We installed one module — body-parser
— but din’t discuss it’s purpose. It provides a middleware — https://medium.com/@adamzerner/how-bodyparser-works-247897a93b90 — Beautifully explain here in this medium post
In short, what it is telling that — data from client is coming in the form of chunks to the server. Server listens to it all the time when it is coming. When it knows that it has received all the data, it listens to it as well and with bodyParser.json()
as a middleware, it then parses the body and assigns it to req.body
at the end
req.body = JSON.parse(data); // data - string .. at the end
Now, that we understand and have configured our express application start point, it’s time we start building our apis for real — Create, Read, Update and Delete
POST /todos — stores a todo in the database
in server/server.js
const express = require('express');const bodyParser = require('body-parser');const {mongoose} = require('./db/mongoose');const {User} = require('./models/user');const {Todo} = require('./models/todo');const app = express();app.use(bodyParser.json());app.post('/todos', (req, res) => {const todo = new Todo({text: req.body.text});todo.save().then((result) => {res.send({result}); // {result: record} .. that is being saved into the database}, (e) => {res.status(404).send();console.log('Error in saving the record - POST - TODOs ', e);});});app.listen(3000, () => {console.log('Listening on port 3000');});module.exports = {app};
So, this code allows us to make a post request at /todos
with the data {"text": "Test"}
and type raw/application-json
from postman.
We will also write test case for this request using supertest module that we have seen in the tests chapter of our nodeJS series.
Testing Api
expect
for assertionsmocha
for writing testssupertest
for testing express applicationsnodemon
to watch for any changes
Run npm install --save-dev nodemon expect@1.20.2 mocha supertest
to install the test related dependencies in our project as dev
Once installed, in server/tests/server.test.js
const expect = require('expect');const request = require('supertest');const {app} = require('../server');const {Todo} = require('../models/todo');beforeEach((done) => {Todo.remove({}).then(() => {done(); // it runs before each test. and it runs the tests only when the done is called}); // removing all the data to give a fresh start});describe('TodoApp Api Tests', () => {describe('POST /todos', () => {it('should create a new todo', (done) => {const text = 'This is a test todo';request(app).post('/todos').send({text}).expect(200).expect((res) => {expect(res.body.result.text).toBe(text);}).end((err, res) => {if (err) {return done(err);}Todo.find().then((results) => {if (!results) {return done('No result found');}expect(results.length).toBe(1);expect(results[0].text).toBe(text);done();});})});});});
in package.json
..."scripts": {"test": "mocha server/**/*.test.js","test-watch": "nodemon --exec \"npm test\""}
...
We can run the tests — npm run test-watch
Branch — 05_Init
One important thing in postman is that we can save our requests in a collection inside the postman to use it in future.
We will be proceeding with further routes in the next part, i.e., GET, DELETE and UPDATE, and their tests respectively.
So, that’s it for this part, stay tuned for the next part. In this part, we discussed about —
- mongoose ORM
- models, validators and defaults
- postman
- POST api with NodeJS
- Testing api
Thanks. See ya :)
Part 6.3 — https://medium.com/@anujbaranwal/nodejs-8-from-scratch-part-6-3-api-development-9b046fed7364
Part 6.4 — https://medium.com/@anujbaranwal/nodejs-8-from-scratch-part-6-4-api-development-38d600a35ad9