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
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
Creating the package.json
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
Launching the install
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
At http://localhost:3000, you get the welcome message
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”
Launching mongo
and creating the database countries_light_app
, mongo is the command-line shell.
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/countriesCaution : 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
Post few countries in the database with Postman
Check the url http://localhost:3000/countries, you should get the list of all the countries inserted in the database.
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
Browse your brand new documentation
All the routes have been documented
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
Running the test with $ npm test
Running the test with $ npm test
with an intentional error just to be sure it is working.
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
- Excellent article. Very inspiring. Building a Restful CRUD API with Node.js, Express and MongoDB
https://www.callicoder.com/node-js-express-mongodb-restful-crud-api-tutorial/ - Documenting APIs using ApiDoc.js by Caio Ribeiro Pereira
https://blog.jscrambler.com/documenting-apis-using-apidoc-js/ - Build Node.js RESTful APIs in 10 Minutes
https://www.codementor.io/olatundegaruba/nodejs-restful-apis-in-10-minutes-q0sgsfhbd - Git repository for Nodejs in 10 minutes
https://github.com/generalgmt/RESTfulAPITutorial - How to Use json-server to Create Mock APIs
https://www.codementor.io/ayushgupta/how-to-use-json-server-to-create-mock-apis-0-lci958ear - Create A REST API With JSON Server
https://medium.com/codingthesmartway-com-blog/create-a-rest-api-with-json-server-36da8680136d - Build a Node.js API in Under 30 Minutes
https://medium.freecodecamp.org/building-a-simple-node-js-api-in-under-30-minutes-a07ea9e390d2 - Very good article in Spanish. Testeo de API REST con Mocha y Chai-HTTP
https://www.paradigmadigital.com/dev/testeo-api-rest-mocha-chai-http/ - Very good article in Spanish. Testeando JavaScript con Mocha y Chai
https://www.paradigmadigital.com/dev/testeando-javascript-mocha-chai/ - Git repository for Testeo de API REST con Mocha y Chai HTTP.
https://github.com/paradigmadigital/ChaiHttp-sample - Excellent Book in Brazilian: Construindo APIs REST com Node.js
https://www.casadocodigo.com.br/products/livro-apis-nodejs - The same in English: Building APIs with Node.js
https://leanpub.com/building-apis-with-nodejs - Git repository for Construindo APIs REST com Node.js by Caio Ribeiro Pereira
https://github.com/caio-ribeiro-pereira/building-apis-with-nodejs - Git repository of Caio Ribeiro Pereira, the author
https://github.com/caio-ribeiro-pereira - Professional Node.js: Building Javascript Based Scalable Software
http://www.wrox.com/WileyCDA/WroxTitle/Professional-Node-js-Building-Javascript-Based-Scalable-Software.productCd-1118185463.html - Introduction to Node.js API Unit Testing with Mocha and Chai
https://ubuverse.com/introduction-to-node-js-api-unit-testing-with-mocha-and-chai/ - Testing APIs with Mocha
https://blog.jscrambler.com/testing-apis-mocha-2/ - Make your node.js api bulletproof: how to test with mocha, chai, and supertest
http://developmentnow.com/2015/02/05/make-your-node-js-api-bulletproof-how-to-test-with-mocha-chai-and-supertest/ - Testing Node.js with Mocha and Chai
http://mherman.org/blog/2015/09/10/testing-node-js-with-mocha-and-chai/#.Wu1ad9OFMWo - Unit test your Nodejs RESTful API using mocha
https://javascript.tutorialhorizon.com/2014/09/14/unit-test-your-nodejs-restful-api-using-mocha/ - Good article. BDD in JavaScript: Getting Started with Cucumber and Gherkin
https://www.sitepoint.com/bdd-javascript-cucumber-gherkin/ - The evolution journey of Android GUI testing. Good article (the only article where some feedback and abstraction)
https://medium.com/@sebaslogen/the-evolution-journey-of-android-gui-testing-f65005f7ced8 - Good article. Into the Belly of the Beast: UI Testing an Android App with Cucumber and Espresso
https://medium.com/@Alex_Fogleman/into-the-belly-of-the-beast-ui-testing-an-android-app-with-cucumber-and-espresso-4a65ae61539a
- CucumberEspressoDemo
https://github.com/emmasuzuki/CucumberEspressoDemo - Getting Started with TDD in Swift 3
https://medium.com/@ynzc/getting-started-with-tdd-in-swift-2fab3e07204b - End to end Gherkin testing with Cucumber.js and Protractor — make your team amazing
https://medium.com/simdevelopers/end-to-end-gherkin-testing-with-cucumber-js-and-protractor-make-your-team-amazing-4f3e2e1a2adc - Tartare: Code Driven Testing
https://engineering.telefonica.com/tartare-code-driven-testing-ed8b1d4df6d7
- Getting Started with Node.js and Mocha
https://semaphoreci.com/community/tutorials/getting-started-with-node-js-and-mocha - How to run Mocha/Chai unit tests on Node.js apps
https://buddy.works/guides/how-automate-nodejs-unit-tests-with-mocha-chai - UI Testing with Puppeteer and Mocha — Part 1 (Getting Started)
https://medium.com/@ankit_m/ui-testing-with-puppeteer-and-mocha-part-1-getting-started-b141b2f9e21 - How to Build and Structure a Node.js MVC Application
https://www.sitepoint.com/node-js-mvc-application/