Sunday, October 22, 2017

Build a Node.js REST API with Swaggerize-express and host it into an Azure App Service


Introduction

In the 2 previous posts, I showed how to deploy a simple (just GET actions) REST API based on Node.js, Express and Swaggerize-express:
I found the Node.js REST API in a Microsoft documentation, cleaned the code and pushed it in a personal reporitory on Github.
Now's time to show how to generate that code, and I use the word "generate" on purpose because we are going to see that the magic of swaggerize-express is to build a complete Node.js REST API in a few seconds based on the providing of a json template that describes the API. So let's do this now an end to end project:

starting the development of an API from scratch and finally deploying it into Azure so that it be available for anybody!

Prerequisites

  • Node.js
  • Git
  • Visual Studio Code
All the references for installing all that are in the beginning of my two previous posts.

Building the REST API

Installing Swaggerize-express

As described in the Swaggerize-express documentation, first, open a command prompt.
I navigated to my code repository and created a new folder for the project, then I installed swaggerize-express locally.
$ npm install -g yo
$ npm install -g generator-swaggerize






As I had already swaggerize-express installed, it just updated my installed package.

Generating the REST API

Now we are going to generate a complete node.js REST API (although there is just 2 actions using GET verb) based on this descriptive json template. So copy next code (it is not a picture :-)):

{
    "swagger": "2.0",
    "info": {
        "version": "v1",
        "title": "Contact List",
        "description": "A Contact list API based on Swagger and built using Node.js"
    },
    "paths":{
        "/contacts":{
            "get": {
                "tags": ["Contacts"],
                "operationId": "contacts_get",
                "consumes":[],
                "produces":["application/json",
                "text/json"],
                "responses":{
                    "200":{
                        "description":"OK",
                        "schema":{
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/Contact"
                            }
                        }
                    }
                },
                "deprecated": false
            }
        },
        "/contacts/{id}": {
            "get": {
                "tags": ["Contacts"],
                "operationId": "contacts_getById",
                "consumes":[],
                "produces":["application/json",
                "text/json"],
                "parameters":[{
                    "name":"id",
                    "in": "path",
                    "required": true,
                    "type": "integer",
                    "format": "int32"
                }],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "array",
                            "items": {
                                "$ref": "#/definitions/Contact"
                            }
                        }
                    }
                },
                "deprecated": false
            }
        }
    },
    "definitions": {
        "Contact": {
            "type": "object",
            "properties": {
                "id": {
                    "format": "int32",
                    "type": "integer"
                },
                "name": {
                    "type": "string"
                },
                "email": {
                    "type": "string"
                }
            }
        }
    }
}

Create a subfolder in your project folder. It is important to name it "config"
Open the main project folder with Visual Studio Code
Create an api.json empty file in the "config" sub-folder within Visual Studio Code






Paste the template json code in it and save it



We can now generate the REST API.
Go back to your command prompt and type:
$ yo swaggerize
Follow the prompts (note: make sure to choose express as your framework choice).
When asked for a swagger document, give the complete path of your api.json file. In my case
C:\dev\vscode-repo\swaggerize-express-rest-api\config\api.json
Then the magic is starting and Swaggerize-express creates a complete REST API project.







Testing the first version of our REST API generated with Swaggerize-express

and we can test it right now by typing:
node server.js



and hitting the API within Chrome to have the json display in the browser, as defined in the server.js file:
http://localhost:8000/contacts



A mocked data generator is integrated with swaggerize-express that allows to test the API right after its creation.
Next step we are going to adapt this first project into an API with real data, and modify it to make it work within an Azure App Service.

Placing real (mock) data in the API

Understanding the code

Let's try to understand how the API works.
All the calls go first to sever.js, so let's open it. We see this code:
App.use(Swaggerize({
    api: Path.resolve('./config/swagger.json'),
    handlers: Path.resolve('./handlers')
}));
So the calls to the API are driven by the handlers.
  • If we hit the API url/contacts, the handlers\contacts.js file is processing the call.
  • If we hit the API url/contacts/anId, the handlers\contacts\{id}.js file is processing the call.
So let's open first the handlers\contacts.js file to see how it is processing the call. Doing that we learn that it is redirecting the call to data\contact.js.
So let's open this file too. We see that at this location that the mock data is generated by the swaggerize mock data generator and it is said that is the place to connect with our real datas.
We are going to go up from the data source toward the handlers and to develop the capability of our REST API to send our data.

Adding the contacts.json file hosting our mock data

Let's create a contacts.json file under the data folder and place this json data in it:
[
 {
  "id":1,
  "name":"Barney Poland",
  "email":"barney@contoso.com"
 },
 {
  "id":2,
  "name":"Lacy Barrera",
  "email":"lacy@contoso.com"
 },
 {
  "id":3,
  "name":"Lora Riggs",
  "email":"lora@contoso.com"
 }
]





Adding the contactsDataHandler.js file for serving our mock data

Rename the \data\contacts.js file to contactsDataHandler.js and add this code in it:
'use strict';

var contacts = require('./contacts.json');

module.exports = {
    all: function () {
        return contacts;
    }
};



Updating the code in handler\contacts.js file for serving our mock full data

Then, replace the code of the handlers\contacts.js file (a kind of controller) by this one:
 
'use strict';

 var contactsDataHandler = require('../data/contactsDataHandler');

 module.exports = {
     get: function contacts_get(req, res) {
         res.json(contactsDataHandler.all())
     }
 };




Open a commad prompt, navigate to your project folder and launch the server by typing:
node server.js
(for newbies, to stop the server on Windows type "ctrl c" like if you want to copy something)
At this setp, as the js code is compiled by node.js before launching the server, if you would have made a big coding error, the server wouldn't have started and you would have been provided within the command prompt with a error message with all the stack.



Then, hit localhost:8000/contacts on any browser but Internet Explorer (that serves the json as a file so not very useful for testing)
Hurrah! We can see our real data sent back from the REST API for the first time!



We didn't break the feature for requesting a single contact by its id. It's still working with auto-generated swaggerize mock data.



Now we have to connect the GET contacts/id action to our real data.

Updating the code of contactsDataHandler.js

open contactsDataHandler.js in Visual Studio code and add:
a refence to the npm module jsonpath that will serve us to retrieve a contact based on its id. a function with the id in parameter to retrieve the contact.

here is the updated complete code:
'use strict';

var contacts = require('./contacts.json');
var jp = require('jsonpath')

module.exports = {
    get: function (id) {
        return jp.query(contacts, '$..[?(@.id=='+id+')]');
    },
    all: function () {
        return contacts;
    }
};




Updating the code of contacts\{id}.js

open contacts\{id}.js file in Visual Studio code and replace the code in it by this one:
 'use strict';

 var repository = require('../../data/contactsDataHandler');

 module.exports = {
     get: function contacts_get(req, res) {
         res.json(repository.get(req.params['id']))
     }    
 };




testing the action GET/contacts/id

We can test the developed code now but before to do that we have to install the npm jsonpath module we declared and used in the contacts dataHandler.
So type: npm install jsonpath in your command prompt.



Then we can test and get the excpeted result



Deleting mockgen.js

we can now delete the mockgen.js file because we don't need it anaymore sinc all is pointing on our real data stored in our contacts.json file.
At this step the project should look like this on your machine:



Well done! the last thing to do is to deploy all this in Azure and the job is done.

Deploying the Swaggerize REST API into an Azure App Service

Last update before deploying, server.js file

We are going to use for this deployment the "Try Azure App Service" feature that offers to take benefit of the Azure portal very quickly for one hour. You just have to have one of this social account (Microsoft, Google, Facebook, Github.

But before opening an one hour trial for the Azure App Services we have to prepare our project for the deployment.
The App Service we are targetting for deploying is a Node.js Web App. It is not empty and has allready all lot of files, and by chance its main file is also a file called server.js so that it will be overwritten by the server.js file of our project when deploying.
Unfortunately, our server.js file generated automatically by Swaggerize-express isn't totally compliant with this Azure Node.js Web App we are tragetting for deploying. We thus have to update our server.js file.
So open it in your editor and replace its code with the following:
'use strict';

var port = process.env.PORT || 8000; // first change

var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');
var swaggerize = require('swaggerize-express');
var swaggerUi = require('swaggerize-ui'); // second change
var path = require('path');

var app = express();

var server = http.createServer(app);

app.use(bodyParser.json());

app.use(swaggerize({
    api: path.resolve('./config/api.json'), // third change
    handlers: path.resolve('./handlers'),
    docspath: '/swagger' // fourth change
}));

// change four
app.use('/docs', swaggerUi({
  docs: '/swagger'  
}));

server.listen(port, function () { // fifth and final change
});




If we want to test locally a last time before deploying we have first to install swaggerize-ui npm module. It is also important for Azure because this local installation will be tracked in our local project and tell Azure that the module is needed within the Azure environment.



Creating the "Try Azure App Service" Azure App Service to host the project

So let's deploy our Node.js REST API into this type of Azure App Service, totally free and without any commitment For enjoying this Azure feature, reach the welcome page of "Try Azure App Service"



You are then invited to choose the type of App Service you want to try. Let's start with a Web App. You will see that you can totally use a Web App for hosting a REST API, Node.js will appear at the next step. Select the Web App, then click Next.



Let's choose the Node.js + Express now. Click on "Create".
As wrritten previously you can use one of the 4 social networks account to sign in : Microsoft (live), Google +, Facebook, Github. For the demonstration I will use my Live account.





Then, Azure is provisionning your App Service in a few seconds.



And an ONE Hour countdown is starting lettting you play with the Azure App Service and the Azure Portal within this hour.



Creating a .gitignore file

We have to prepare the deployment with another step. We have to exclude the thousand files of the npm modules installed locally in our project to prevent them to be deployed in Azure. Azure has them anyway or can get them at the deployment time much more faster than to deploy them from our local machine.
Create a gitignore.txt file at the root of your project and paste: node_module/ in it



Then shift right-click your folder (not a file) and select "open a powershell window from here" in the contextual menu.



In the powershell type: ren gitignode.txt .gitignode.



Deploying the Swaggerize-express API into Azure

Open the Integrated Terminal of visual studio code.





type
git init . to initialize the git feature for the deployment



Check with
git status
that the files under node_modules would be excluded



then type
git add .
to add all the files references to the future deployment
All the files of node_modules should not be taken into account but they were added to the .git repo anyway and a warning occured. Don't worry about that. I think they won't be deployed at the push moment.



Now commit all the changes to prepared them to be pushed in Azure. All is new so type:
git commit -m "initial version"



While the commit is finished (there again all the files even those of the node_modules were processed), it's time to deploy, so we are going to add the reference to our Azure App Service
Go back to the "Try Azure App Service" welcome page were the countdown is running and pick the git url by clicking on the "clone or push with git" button. Copy the url in your clipboard.



Then type
git remote add azure
and right click the Integrated Terminal to paste the Azure App Service git url



then for deploying, type:
git push azure master





The deployment was successful although all was deployed even the files under the node_modules folder.
We can check the deployment by visiting the Visual Studio Code online and notice that we are retrieving exactly the same experience than locally





If we hit the run button of the editor the Web App is launched and some traces are written on the Output console.
You will get an error on the root site because we didn't implement the GET site/ route, but if you complete the root site url with /contacts you will have the pleasure to notice that everyhting is ok.



and also for the GET contcts/id action



Performing development tasks on line

What is super cool with Node.js and Azure Web App is that you can modify everything online. I add myself as a new contact.



and it worked perfectly well



Testing the Azure REST API with swagger

Last we can use swagger to test our API online.
The right Url to display our API in Swagger UI is

yourAzureAppUrl/docs/?url=/swagger#/contacts



If you do this end to end it would be nice to tell me how long it took so as I can refer it at the beginning of the post.
Enjoy folks!