Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Invoice Application Using Electron and ApsaraDB for MongoDB - Part 2

DZone's Guide to

Invoice Application Using Electron and ApsaraDB for MongoDB - Part 2

In this post, we wrap up our series by looking at how to create the backend for the app we started last time and how to connect to a database.

· Web Dev Zone ·
Free Resource

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

Written by Sai Sarath Chandra, Alibaba Cloud Tech Share author. Tech Share is Alibaba Cloud’s incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

In our previous tutorial, we have created the UI for our Invoice Application. However, as discussed in our first article, desktop applications face the risk of losing valuable data.

Therefore, we will be using Alibaba Cloud’s ApsaraDB for MongoDB to save our data onto the cloud. By storing your data on the cloud, you can use this data across applications like Android, iOS, and web applications, as well as obtain the data at any time. Alibaba Cloud ensures that the data is readily available every time. You can also leverage the Automatic Elastic Scaling provided by Alibaba Cloud to suit your business at any time.

Setting Up the Application Backend

Now we will discuss on the backend we are creating for the invoicing Application.

The API we are creating is based on a Node server and the Express.js framework.

Clone the code from GitHub and navigate to the “Invoice_Backend” folder. Open the file using your favorite text editor.

There are only two files for our interest:

  • Package.json: This file holds all the information regarding the dependencies, such as development dependencies.
  • Server.js: This is the key file where we write the logic. In production scenarios, it is recommended to use the frameworks like Loopback to have a high-performance API with much more control.

In Package.json, we have a standard set of dependencies:

  • Sprint-JS, mongoDB, node-UUID, formidable – for connecting to the database and creating the URLs at runtime.
  • Express and body-parser – are used to create the APIs and get the incoming request in a JSON format.

In Server.js, we have the following code

 http.createServer(app).listen(443, function () {
  console.log('Server for Invoice Backend running on port 443!');
});

The above is the standard set of ways to create an HTTP server listening at 443 for requests. Make sure you have the below imports before starting off.

const bodyParser = require("body-parser");
const express = require("express");
const app = express();
var uuid = require('node-uuid');
var http = require('http');
var fs = require('fs');
var sprintf = require("sprintf-js").sprintf;
var mongoClient = require('mongodb').MongoClient;

All these imports are needed for the application to perform normally.

app.use(bodyParser.json());

This line above will unparse the body information which we send into JSON format before it goes through the database - otherwise, it results in an error.

Here I am using the console in that way so that you can see the information as soon as the application passes the console.log() line and understands what’s happening here. In production, it is not advisable to have console statements. Instead, you will have a proper logging format to achieve this end.

// ApsaraDB for MongoDB related configurations
var host1 = "dds-6gj540e0c157941.mongodb.ap-south-7.rds.aliyuncs.com";
var port1 = 3012;
var host2 = "dds-6gj54080c157942.mongodb.ap-south-7.rds.aliyuncs.com";
var port2 = 3012;
var username = "root";
var password = "Mongodb@12345";
var replSetName = "mgset-1050000641";
var demoDb = "admin";

Your MongoDB related information needs to go through here to connect and perform operations on your database.

app.post('/data/invoice', (req, res) => {
  console.log(req.body);   
  var saveData = saveInvoiceData(req.body); 
  saveData.then(function(dbResponse){
    console.log(dbResponse);
    res.status(201).send(dbResponse);

  },function(err){
    console.log(err);
    res.status(400).send(err);
  });
});

This is the POST operation which happens when they click the submit button on the application. Internally, it calls saveInvoiceData.

The saveInvoiceData method will connect to the DB, authenticate, find the collection and push data into the DB.

function saveInvoiceData(collectionData) {

  console.log(collectionData);
  return new Promise(function (resolve, reject) {
    // Logic to fetch from the MongoDB
    mongoClient.connect(url, function (err, db) {
      //if error console error
      console.log(err);
      if (err) {
        // Database not connected : error thrown
        console.error("connect err:", err);
        reject(err);
      } else {
        //Database connected successfully, get the DB Object
        var adminDb = db.admin();
        //Authenticate Database
        adminDb.authenticate(username, password, function (err, result) {
          if (err) {
            console.log("authenticate err:", JSON.stringyfy(err));
            reject(err);
          } else {
            console.log('Authenticated : ', JSON.stringify(result));
            // Get the Collection handle.
            var collection = db.collection("saleData");
            collection.insertOne(collectionData,function(err,result){
              if(err){
                reject(err);
              }else{
                resolve(result);
              }
            });
          }
        });
      }
    });
  });
}

The method receives a collectionData JSON object. And the other information is obvious from the method comments. Notice here that the data is pushed into the collection, saleData.

The below is the GET method for getting the data related to the dashboards:

app.get('/data/dashboard', (req, res) => {
  var getData = getDashboardData();
  getData.then(function(result){
    res.status(200).send(result);
  },function(err){
    console.log(err);
    res.status(400).send(err);
  });
});

The GET method calls the getDashboardData() method to fetch the data, process it, and create a response.

function getDashboardData() {

  return new Promise(function (resolve, reject) {
    // Logic to fetch from the MongoDB
    mongoClient.connect(url, function (err, db) {
      //if error console error
      console.log(err);
      if (err) {
        // Database not connected : error thrown
        console.error("connect err:", err);
        reject(err);
      } else {
        //Database connected successfully, get the DB Object
        var adminDb = db.admin();
        //Authenticate Database
        adminDb.authenticate(username, password, function (err, result) {
          if (err) {
            console.log("authenticate err:", JSON.stringyfy(err));
            reject(err);
          } else {
            console.log('Authenticated : ', JSON.stringify(result));
            // Get the Collection handle.
            var collection = db.collection("saleData");
            collection.find({}).toArray(function (err, items) {
              if (err) {
                console.error('Unable to find data' + JSON.stringify(err));
              } else {
                console.info('data Fetched from MongoDB');
                var response = {}; 

                var datesArr = [];
                var salesArr = [];
                var ordersArr = [];

                var i =0;
                for(i=0; i<5; i++){
                  var totalSales = 0;
                var totalOrders = 0;
                  var d = new Date();
                  d.setDate(d.getDate() - i);
                  var month = d.getMonth() + 1;
                  var day = d.getDate();
                  var output = d.getFullYear() + '/' + (month < 10 ? '0' : '') + month + '/' + (day < 10 ? '0' : '') + day;
                  datesArr.push(output);
                console.log("In Loop 1 : "+i);
                  for(var k=0; k<items.length; k++){
                    var item = items[k];
                    if(item.invoiceDate == output){
                      totalSales = totalSales + item.totalAmount;
                      totalOrders = totalOrders+1;
                    }
                  }
                  salesArr.push(totalSales);
                  ordersArr.push(totalOrders);
                }
                response.datesArr = datesArr;
                response.salesArr = salesArr;
                response.ordersArr = ordersArr;
                resolve(response);
              }
            });
          }
        });
      }
    });
  });
}

There is a lot going in here. If you hit the below mentioned URI, you will see the following information.

Request : GET
http:// VM IP : PORT>/data/dashboard

Response :

{
    "datesArr": [
        "2018/03/25",
        "2018/03/24",
        "2018/03/23",
        "2018/03/22",
        "2018/03/21"
    ],
    "salesArr": [
        0,
        4197.3,
        34,
        0,
        0
    ],
    "ordersArr": [
        0,
        1,
        1,
        0,
        0
    ]
}

In the  getInvoiceData() method, once the database is connected, data is authenticated and fetched from the collection. The method will run a loop to check the number of orders and total sale value for the last 5 days from the current data and push that data into corresponding arrays.

The above-mentioned response is sent to the /GET method so it will run a for loop on the entire data and constructs the response into corresponding arrays. Since this will be a CPU intensive task we have externalized it to the middleware deployed on an Alibaba Cloud ECS instance.

Before moving on, you need to integrate your application into the endpoint to make sure the data you receive will be in the proper format. I have used Postman, which is a simple client for that purpose.

Postman

The below is a screenshot of a Postman window:

1

  • You can call have different methods like GET, POST, PUT, PATCH, DELETE.
  • There is a URI/address bar which also accepts the query parameters.
  • Click the send button to make the request and get the response.
  • You can explore more, you can run test cases or peak performance testing. This is a free tool you can use.

Deploying the API

You should already have an Alibaba Cloud ECS set up. You can check out other tutorials on creating an ECS instance if you aren't sure about it.

Creating a MongoDB Instance:

  1. You need to activate ApsaraDB for MongoDB in your Alibaba Cloud console.

  2. Navigate to the ApsaraDB for MongoDB console and choose the appropriate zone.

  3. Click on Create Instance.

  4. Carefully select all the infrastructure related configurations like RAM and Bandwidth.

  5. If you are using a password, keep it safe for future use/reference. We will be using it in our code for authentication.

  6. Preview and create the instance by accepting the terms and conditions.

  7. Once your instance is created, navigate to the details of the instance and whitelist your ECS instance IP.

  8. Once you navigate to the whitelisting rules, you will see an Import ECS IP button. Upon clicking the button, the ECS Intranet IP will be imported automatically.

  9. In a few seconds, you should be able to see the “Connection String” appearing on the console. You can use this information to connect GUI MongoDB Clients to ApsaraDB for MongoDB.

  10. Other individual information is needed to connect to MongoDB through code. Make sure you replace this information in the code to connect to your database.

Running the Code

After you copy the code to the ECS instance, you have to run the following commands for successful execution:

npm install - This package downloads and installs all the required packages from the npm repository.

npm start / node app.js - This will run the application and once the server is started, you should be able to invoke the API.

Conclusion

During this article series, we have seen what Electron is and we have created a user interface along with a backend API. We also saw how we can leverage ApsaraDB for MongoDB for desktop applications which provides a valuable addition to the product we are creating for our customers.

The whole code is provided in the GitHub repository. If you have questions about something please raise them as an issue at the following link.

If think you can improve the code, please raise it as a pull request.

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

Topics:
electron ,cross-platform app development ,mongodb ,web dev ,backend development

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}