Node, API, Postman – Build a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

These latest months, I have made a lot of research on Testing an API. I dug deep into Mocha, Chai, Postman and Newman. I have also taken a large breath and dived into the Node’s world as it is the quickest way to build an API.
The idea of this post, it is to strengthen the ability for non-developer to structure a POC for an API with the maximum of accuracy.

I believe that, especially for a non-developer such as PO for instance, there is a strong correlation between testing new features and improving the design process of a product. How can I as a PO add a new feature to my product for instance a mobile application if I am not able to test it correctly. Indeed, the test implies that have a clear idea of what the new feature has to do. If I am unable to test it by writing down a gherkin feature, I am probably unable to express my need. My other concern was also how can I spark off my interest for testing, overcome the difficulty to learn Chai for instance and embrace the culture of testing.

The code is available on github at https://github.com/bflaven/node-countries-light-app

As I am not considering myself as a developer, I always pay a lot of attention of what is implicit in the given explanations of a post dedicated for instance on how build a Node API. Most of the posts that have read are stuffed with useful but implicit information. Here is the reason why I am making this quick digest of its, avoiding as far as I can plagiarism and adding 2 plus : a test strategy and a way to handle documentation with Apidoc.

Be sure before you start, to ensure that you have npm and mongo installed. Just go in the console and type the following commands.

$ npm -v
$ mongo --version
$ node -v

If Homebrew, Node or Mongo are not installed. Here the shortest procedure to install all requirements on a Mac. Very brief but you got the essentials, if you have already installed these tools, you can jump to the point 1.

  • Install Postman: Check https://www.getpostman.com/apps
  • Install Homebrew: Check https://brew.sh/. Launch in the console:
    $ /usr/bin/ruby -e "$(curl -k -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  • Install Node and NPM:
      $ brew update
      $ brew doctor
      $ export PATH="/usr/local/bin:$PATH"
      $ brew install node

    Source: https://changelog.com/posts/install-node-js-with-homebrew-on-os-x

  • Install Newman globally:
      $ npm install -g newman

    . Source: https://support.getpostman.com/hc/en-us/articles/115003703325-How-do-I-install-Newman-

  • Install MongoDB:
    $ brew update
    $ brew install mongodb

    At the root of your computer, create the default directory*.

      $ mkdir -p /data/db

    * Run without specifying paths: If your system PATH variable includes the location of the mongod binary and if you use the default data directory (i.e., /data/db), simply enter mongod at the system prompt: mongod.

    Source: https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/

1. SETTINGS

First of all, the content that the API decide on a semantic point of view what you are going to use in terms of wording both for the MVC of your Node application and the database for mongodb. In my case, I am working with countries, so I may need to use for the MVC something like country!

As you will a create a countries dedicated to countries, be sure to thing of using country or countries as « prefix » as much as possible and so On

Here is future name of for my coming controller, model, route: country.controller.js, country.model.js, country.routes.js

Here the name for the database in mongodb: countries_light_app
The directory and appName: node-countries-light-app

2. CREATING A SIMPLE APP

To ensure that you are in the correct directory of the app

$ pwd
$ cd /[path-in-your-environment]
$ mkdir node-countries-light-app
$ cd node-countries-light-app

In the application directory node-countries-light-app
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Launch the installation with npm, by default this will load the content of package.json

$ npm install

In the console, go the directory where you want to create your app directory node-countries-light-app

You will define the characteristics of your application and then you will get the famous package.json file with the basics information of your node application.

  • The value for the name: node-countries-light-app
  • The value for the description: Yallah Yallah, Welcome to Country Light App. A prototype to play with Countries.
  • The values for the keywords: Node, Express, RestAPI, MongoDB, Mongoose, Countries

Be sure to be in your application directory node-countries-light-app and type this command.

$ npm init

After a simple step by step, you should get a package.json created with npm init like this one below:

{
  "name": "countries-light-app",
  "version": "1.0.0",
  "description": "Yallah Yallah, Welcome to Country Light App. A prototype to play with Countries",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "Node",
    "Express",
    "RestAPI",
    "MongoDB",
    "Mongoose",
    "Countries"
  ],
  "author": "bflaven",
  "license": "ISC"
}

Creating the package.json
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Creating the package.json
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Install the Node elements that are required to make your application working

$ npm install express body-parser mongoose --save

Your application directory node-countries-light-app now has a package.json file and a node_modules folder and should look like this:

node-countries-light-app/
|-- _node_modules/
    |-- ...    
|-- package.json

Launching the install
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Launching the install
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Create the server file for your Node application

$ touch server.js

Insert this code into the file server.js

  /* server.js V1 */
const express = require('express');
const bodyParser = require('body-parser');
 
// create express app
const app = express();
 
// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true }))
 
// parse requests of content-type - application/json
app.use(bodyParser.json())
 
// define a simple route
app.get('/', (req, res) => {
    res.json({"message": "Yallah, Welcome to Country Light App. A prototype to play with Countries"});
});
 
// listen for requests
app.listen(3000, () => {
    console.log("Country Light App is up & the server is listening on port 3000");
});

Your application directory node-countries-light-app should look like this:

node-countries-light-app/
|-- _node_modules/
    |-- ...    
|-- package.json
|-- package-lock.json
|-- server.js

So far, you can launch the Node application with the following command. It should work! The application is available at http://localhost:3000

$ node server.js

The first version of the app is running on http://localhost:3000
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

At http://localhost:3000, you get the welcome message
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

3. SOPHISTICATING THE APP

Create the config file for the database of your Node application

$ mkdir config
$ cd config
$ touch database.config.js
/* database.config.js */
 
module.exports = {
    url: 'mongodb://localhost:27017/countries_light_app'
}

Launching mongod, mongod is the « Mongo Daemon »
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Launching mongo and creating the database countries_light_app, mongo is the command-line shell.
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Your application directory node-countries-light-app should look like this:

node-countries-light-app/
|-- _config/
    |-- database.config.js  
|-- _node_modules/
    |-- ...    
|-- package.json
|-- package-lock.json
|-- server.js

Create the structure for the application.

$ mkdir -p app/models
$ cd app/models
$ touch countrie.model.js
 
$ mkdir app/routes
$ cd app/routes
$ touch countrie.routes.js
 
$ mkdir app/controllers
$ cd app/controllers
$ touch countrie.controller.js

Be sure to have the following directory in your application directory node-countries-light-app

node-countries-light-app/
|-- _app
    |-- _controllers/
        |-- countrie.controller.js
    |-- _models/
        |-- countrie.model.js
    |-- _routes/
        |-- countrie.routes.js
|-- _config
    |-- database.config.js
|-- _node_modules/
    |-- ...
|-- package.json
|-- package-lock.json
|-- server.js

4. CREATE THE DB

In a first window of the terminal, launch the daemon of Mongo

$ mongod

Get into the Mongo shell

$ mongo

Print a list of all databases on the server

$ show dbs;

Use the database, just by typing this command it will create the required database

$ use countries_light_app;

Source : https://docs.mongodb.com/manual/reference/mongo-shell/

5. USING POSTMAN


In postman, I have a set of queries to request this new API, leveraging on the Postman’s ability to manage environment and also to store the queries so I do not have to redo the queries again and again.

5.1 USING A POSTMAN’S FILE ENVIRONMENT


The name for file environment that is imported in Postman under the name ENV_NODE_COUNTRIES_LIGHT_APP. The file is named env_node_countries_light_app.postman_environment.json and it contains the 2 variables {{api_root_url}} and {{api_root_url_countries}}

{
  "id": "a23b2611-4076-4ea2-9ad8-9b79bccbe316",
  "name": "ENV_NODE_COUNTRIES_LIGHT_APP",
  "values": [
    {
      "key": "api_root_url",
      "value": "http://localhost:3000",
      "enabled": true,
      "type": "text"
    },
    {
      "key": "api_root_url_countries",
      "value": "http://localhost:3000/countries",
      "enabled": true,
      "type": "text"
    }
  ],
  "_postman_variable_scope": "environment",
  "_postman_exported_at": "2018-05-22T13:48:34.707Z",
  "_postman_exported_using": "Postman/6.0.10"
}

5.2 USING A POSTMAN’S FILE COLLECTION

I also export all the queries into a postman’s collection in Postman
in the file node_countries_light_app.postman_collection.json. There are 6 queries for CRUD operations.

  • The first query: 1_welcome_api
    Description: It outputs the welcome message.
    Method: using GET at http://localhost:3000
  • The second query: 2_post_country_api
    Description: It enables to post a country in the database
    Method: using POST at http://localhost:3000/countries

    Caution : Here some records to send via Postman to not have an empty database before you try to load this page.

    { "name":"Afghanistan", "tld":".af", "cca2":"AF", "capital":"Kabul", "callingCode":"93" }
    { "name":"Italy", "tld":".it", "cca2":"IT", "capital":"Rome", "callingCode":"39" }
    { "name":"France", "tld":".fr", "cca2":"FR", "capital":"Paris", "callingCode":"33" }
    { "name":"Malaysia", "tld":".my", "cca2":"MY", "capital":"Kuala Lumpur", "callingCode":"60" }
    { "name":"Mauritania", "tld":".mr", "cca2":"MR", "capital":"Nouakchott", "callingCode":"222" }
    { "name":"Tunisia", "tld":".tn", "cca2":"TN", "capital":"Tunis", "callingCode":"216" }
    { "name":"Tanzania", "tld":".tz", "cca2":"TZ", "capital":"Dodoma", "callingCode":"255" }
    { "name":"Seychelles", "tld":".sc", "cca2":"SC", "capital":"Victoria", "callingCode":"248" }
    { "name":"Norway", "tld":".no", "cca2":"NO", "capital":"Oslo", "callingCode":"47" }
    { "name":"Nepal", "tld":".np", "cca2":"NP", "capital":"Kathmandu", "callingCode":"977" }
  • The third query: 3_get_all_countries_api
    Description: List all the countries
    Method: using GET /countries
  • The fourth query: 4_get_single_country_id_api
    Description: Retrieving a single Country eg 5afd8c9cad99cd0a44dfc3aa
    Method: using GET /countries/:countryId
    Caution: The id is random so be sure to use the proper id created for each country by the insertion in the database.

  • The fifth query: 5_put_update_single_country_id_api
    Description: Updating a Country eg 5afd8c9cad99cd0a44dfc3aa
    Method: using PUT /countries/:countryId
    Caution: The id is random so be sure to use the proper id created for each country by the insertion in the database.

    Update with the data in Italian and not in English

    { "name":"Italia", "tld":".it", "cca2":"IT", "capital":"Roma", "callingCode":"39" }

    Bring back in English if needed

    { "name":"Italy", "tld":".it", "cca2":"IT", "capital":"Rome", "callingCode":"39" }
  • The sixth query: 6_delete_single_country_id_api
    Description: Deleting a Country using the countryId
    Method: using DELETE /countries/:countryId
    Caution: The id is random so be sure to use the proper id created for each country by the insertion in the database.

Restart the application with the database with $ node server.js
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Post few countries in the database with Postman
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Check the url http://localhost:3000/countries, you should get the list of all the countries inserted in the database.
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

6. THE DOCUMENTATION USING APIDOC

Fine, you have an API but believe me it is useless without documentation because nobody will get their hands dirty with your API if it is not documented. Here is a nice easy way to create documentation with the help of the comments inside the code.

To start our documentation process, first you need to create a descriptor file called apidoc.json inside your app directory.

$ cd /[path-in-your-environment]/node-countries-light-app/
$ touch apidoc.json

apidoc.json required theses attributes. You can add this content for instance in the file apidoc.json

{
    "name": "Yallah Yallah, Welcome to Country Light App",
    "version": "1.0.1",
    "description": "Country Light App, a prototype to play with Countries",
    "template": {
        "forceLanguage": "en"
    }
}

Create the directory for the documentation (/public/apidoc) inside your app directory

$ mkdir public
$ cd public
$ mkdir apidoc

Add this line to your file server.js

// Serving static files from "public" folder.
// Will be useful for apidoc
app.use(express.static('public'))

Be sure to have the following directory in your application directory node-countries-light-app

node-countries-light-app/
|-- _app
    |-- _controllers
        |-- countrie.controller.js
    |-- _models
        |-- countrie.model.js
    |-- _routes
        |-- countrie.routes.js
|-- _config
    |-- database.config.js
|-- _node_modules
    |-- ...  
|-- _public
    |-- apidoc
        |-- ...
|-- apidoc.json
|-- package.json
|-- package-lock.json
|-- server.js

Apidoc by default is reading the comment that are written in the route file for instance. In my case, it will be country.routes.js. You have to type some comments params provided by apidoc. You can do such operation for each route you want to document

// Create a new Country
 
/**
    * @api {post} /countries Register a new country
    * @apiGroup Countries
    * @apiParam {String} countries.name Country name
    * @apiParam {String} countries.tld Country tld
    * @apiParam {String} countries.cca2 Country cca2
    * @apiParam {String} countries.capital Country capital
    * @apiParam {Number} countries.callingCode Country callingCode
    * @apiParamExample {json} Input
    *    {
    *   "name": "Tunisia",
    *   "tld": ".tn",
    *   "cca2": "TN",
    *   "capital": "Tunis",
    *   "callingCode": "216"
    * }
    * @apiSuccess {Number} countries.id Country id
    * @apiSuccess {String} countries.name Country name
    * @apiSuccess {String} countries.tld Country tld
    * @apiSuccess {String} countries.cca2 Country cca2
    * @apiSuccess {String} countries.capital Country capital
    * @apiSuccess {Number} countries.callingCode Country callingCode
    * @apiSuccess {Date} countries.createdAt Update's date
    * @apiSuccess {Date} countries.updatedAt Register's date
    * @apiSuccessExample {json} Success
    *    HTTP/1.1 200 OK
    *    {
    *   "_id": "5b041ac6e3333f03fee37042",
    *   "name": "Tunisia",
    *   "capital": "Tunis",
    *   "tld": ".tn",
    *   "cca2": "TN",
    *   "callingCode": 216,
    *   "createdAt": "2018-05-22T13:27:34.919Z",
    *   "updatedAt": "2018-05-22T13:27:34.919Z",
    *   "__v": 0
    * }
    * @apiErrorExample {json} Register error
    *    HTTP/1.1 500 Internal Server Error
 */

Source : http://apidocjs.com/#params

Install and generate the documentation using apidoc

$ npm install apidoc --save
$ apidoc -e "(node_modules|public)" -o public/apidoc

The content created by apidoc will be in the output directory public/apidoc and it will be available at http://localhost:3000/apidoc

Generate the documentation
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Browse your brand new documentation
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

All the routes have been documented
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

7. RUNNING THE TESTS

Create the directory the test directory inside your application

$ mkdir test
$ touch test/test_the_api.js
node-countries-light-app/
|-- _app
    |-- _controllers
        |-- countrie.controller.js
    |-- _models
        |-- countrie.model.js
    |-- _routes
        |-- countrie.routes.js
|-- _config
    |-- database.config.js
|-- _node_modules
    |-- ... 
|-- _public
    |-- apidoc
        |-- ... 
|-- test
    |-- test_the_api.js
|-- apidoc.json
|-- package.json
|-- package-lock.json
|-- server.js

Install Mocha, Chai and SuperTest with npm

$ npm install mocha chai supertest --save

Do not forget to add this line to your file package.json to enable the test

"scripts": {
    "test": "mocha test/*.js --timeout 15000"
  },

Launch the tests. It will read all the .js file inside the test directory.

$ npm test

Intentionally, I have made an error in the first test to be sure that is currently testing the welcome message. Just in case.

expect(res.body.message).to.equal("Hello, hello, Yallah, Welcome to Country Light App. A prototype to play with Countries");
expect(res.body.message).to.equal("Yallah, Welcome to Country Light App. A prototype to play with Countries");

Installing mocha, chai and supertest
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Running the test with $ npm test
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

Running the test with $ npm test with an intentional error just to be sure it is working.
Node, API, Postman - Buid a simple but complete REST API with Node, tested with Chai and Newman, documented with Apidoc

8. AN EXTRA LINE AND THE CONCLUSION

To use the command npm start, you can add this line to your file package.json

  "scripts": {
    "start": "node server.js",
    "test": "mocha test/*.js --timeout 15000"
  },

I believe, it is a true A to Z manual of creation for a Node API. I try to shrink as much as possible the technical explanations and give the logic of a true step by step so anyone can decide to build a full documented API-POC with Node.

If you download the application from github, just launch the installation with the help of file package.json with the following command.

$ npm install
$ git clone https://github.com/bflaven/node-countries-light-app.git
$ cd node-countries-light-app
$ npm install

After this, you can jump directly to the point 4. CREATE THE DB

Read more