How to Build a Microservices Architecture With Node.Js to Achieve Scale?
To run the application smoothly, it is essential to convert the large, homogeneous structure into small, pieces of program— do this with Node.js.
Join the DZone community and get the full member experience.Join For Free
What Are Microservices?
In software application development, microservices are a style of service-oriented architecture (SOA) where the app is structured on an assembly of interconnected services. With microservices, the application architecture is built with lightweight protocols. The services are finely seeded in the architecture. Microservices disintegrate the app into smaller services and enable improved modularity.
Compared to its predecessor, the monolithic architecture, microservices are hands down more beneficial. You don’t need to stuff all software components and services in one big container and pack them tightly. With microservices, you can build an app with:
- Greater flexibility.
- High scalability.
- Continuous development.
- Systematic data organization.
- Time optimization.
When you build applications on a monolithic architecture, the entire application needs to be deployed with every update. On the other hand, microservices have no dependency on the type of framework, technique or programming language being used to build them. Your ability to release REST-ful APIs for communication and other services is the only requisite for microservice architecture.
The Node.js Platform
Reasons for Using Node.Js for Building Microservices
Key Benefits of Node.js
- Single-threaded: With event looping, the server uses a non-blocking mechanism to respond.
- Event-driven: ‘Events of Node.js’ is a notification system that enables the application server to capture the response of the previous API call.
- Buffer-less: There is no buffering as data is simply released in chunks.
- Asynchronous: The non-blocking, non-synchronous Node.js libraries move to the next API and do not await the return data of the previous API.
- Highly-scalable: Servers can handle as many requests as coming their way.
- Licensed: The program is authorized under a software license.
Microsoft, PayPal, Uber, eBay, and Yammer are leading companies actively using Node.js application development for their projects.
Building Microservices With Node.js
To understand the process better, let’s use Node.js to build a microservice for connecting external APIs. As the development progresses, improvements will be made to make the microservice more responsive and cost-effective.
1. Assess the Business Need
To build this microservice, let’s assume that a business requires a service that identifies two ZIP codes and provides the distance between them. The distance is calculated in miles. You’ll need to use validation techniques for ZIP code identification and distance calculation. The requirement wants the service to configure external API calls. And, it is essential to quickly duplicate calls and make the process more cost-efficient. For this, an internal cache can be implemented.
To begin with, install Node.js on your computer or workstation. Installing the Node.js
NPM (Node.js packet manager) is included in the installation suite. There are several stages where you need to use the NPM. For building this microservice, NPM will be used for launching the project, loading the dependencies, and executing the service.
To initialize the project,
- Open the Node.js platform.
- Go to the root folder.
- Run the command: $ npm init.
Executing the command initiates the walk-through for package.json file creation. By creating the package.json, the project establishes its foundation. The name and version of the service are entered, or you can choose from the defaults and update later.
The microservice will be built on two primary packages — Request and Express.
The Request package enables the microservice to set up a connection with third-party, web-based APIs.
The Express package is a structure for Node applications used for supporting the Node.js foundation of the microservice.
To add these packages to the package.json file,
- Enter the command: $ npm install express request.
- At the end of the command, add: —save.
- Run the command.
The npm init command has developed a structure of files and folders for creating the microservice. The primary file is called server.js. API support files are stored in the API folder. Third-party API connection logic is saved in the service folder. Other key folders include node_modules, package-lock.json, and package.json.
The Express and Request packages are saved to this structure as dependencies in the node_modules folder.
Now, the coding for microservice can begin.
3. Setting Up the Server
The first part of the coding involves building a server that recognizes and accepts the requests. For this, you need to begin with the server.js file, which is the primary file of the project. The code used to create server.js file goes like this:
The next step would be specifying the routes for response transmission. The server created earlier assigns routes that ensure all requests are processed.
4. Specifying the Routes
Defining the routes is a critical stage in microservice development. The routes are defined by two end-points for dispatching and accepting requests.
The default port specification is valued at 3000. By specifying PORT as the environment variable, you can choose to define the port number (value) based on the system running this application.
In the next stage, a route object is transmitted to the API folder from the routes.js file. While doing so, the app object (created earlier) is carried forward with the routes object. This allows the app to start wiretapping the port that was defined. As this process gets completed, the app displays a message to the console.
Each route defined to the server needs to assigned to a controller object target. To build the controller object, use the two end-points and an about endpoint that provides the application information. For this project, both the ZIP codes will be used as the two parameters defining the path for distance endpoints. When the target is assigned, the endpoint displays the distance between the two ZIP codes, calculated in miles.
At this stage of the process, two routes are added to the microservice. The GET requests are transmitted with the first route on the /about endpoint. The function of the controller responds to these requests. The second route processes the GET requests on /distance endpoint, and the controller use the get_distance function to handle them. The two parameters, “zipcode1” and “zipcode2”, are specified respectively.
The controller object that handles these requests is created in the next stage. It is important to exclude the controller object from the server.js file or the routes.js file functions so that all files can access it.
5. Building the Controller
Adding controller logic to the microservice equips it with some interesting functions. A controller object interprets user intentions and actions and communicates the new or modified data to process objects.
For this microservice, a controller object with two properties needs to be created in the controller file. The two properties are nothing but the functions of handling the requests received from the routes module.
By using this code, the properties controller object is created. It references the package.json file created at the first step of this project. With this object, the process object can import and use the informational contents of the package.json file.
The code also has two distinct parts — the about the function and the get_distance function. The first functionality accepts response objects and requests. For executing the about functionality, a new object from the package.json file is returned as a response object.
The get_distance functionality syncs the distance module with the find function (also called the callback function). It accepts the distance objects as well as the error objects. In case of errors, the find function sends back the response object.
6. Establishing the External API Call
Now that the controllers are added, an external service is ready to be executed. This is the final part of the microservice development with Node.js. Here, the third-party API call is handled by the API file. To get the API key, you can get is free from ZIPCODEAPI.com. To make the external call, set an expired test key as the default key.
The code runs the Request package to make the external HTTP request, which needs to be updated for testing error conditions. The code enables the find function to accept the parameters for objects namely—request, response, and next. URL of the service is accepted by the request object. The callback function handles the response object.
“HTTP Status code 200” is the status of the response object, provided there are no errors. The body of the response is parsed out and returned. Instead of forwarding directly, parsing the response allows the response to be handled with maximum efficiency.
Eventually, the distance object is exported, and the controller can represent the concrete instances and functions of the external API calls as needed. To wrap up the execution of this microservice, the code needs to be reviewed for typos in the command.
Challenges of Building Microservices in Node.js
- Unable to process CPU bound tasks: Node.js is single-threaded and cannot compute CPU-heavy tasks. The application experiences performance bottlenecks as the whole CPU bandwidth gets used for processing heavy requests. An experimental feature in Node.js 10.5.0 update has introduced multithreading to fix this challenge.
- Poor NPM tools: Besides the core NPM tools, a majority of tools on the Node.js platform are not properly tested or documented. The registries are unorganized, and the open-source ecosystem is not adequately supervised by Joyent, the creators of Node.js.
- Callback hell: The callback function is heavily used to run each task. When the tasks exceed a limit, the situation leads to a “callback hell” and maintaining the code becomes near-impossible. The code can, however, be simplified and re-factored to lower the impact of the asynchronous nature of Node.js on callback functions.
Published at DZone with permission of Sagar Tambe. See the original article here.
Opinions expressed by DZone contributors are their own.