A Summary for Node.js, socket.io, middlewares, and express.js

Hasan Gökçe
11 min readNov 24, 2020

Node.js is introduced 11 years ago by Ryan Dahi. In 2009, Even if Apache was so popular, it couldn’t handle concurrent requests. For this reason, he developed node.js which is a runtime based on Google’s V8 JavaScript engine. It can be used for creating a web server, streaming, real-time applications, collecting data, browser games, etc. The webserver and scripts run in the same server-side application allow for much stronger integration between the web server and scripts. Also, the webserver can run instantly on the Node.js platform as a Node.js module. This means that it is much easier than creating an Apache server and combining it with server-side scripts.

Google’s V8 engine is a program that converts Javascript code into a lower level or machine code it is open-source and high-performance. V8 implements EcmaScript and can be embedded in any C++ program. Also, it compiles and executes javascript codes besides handling garbage collection and memory allocation for objects.

Among the most popular technologies. According to the StackOverflow user survey, node.js is among the most popular frameworks. It can easily be seen that in the future, a lot of companies will give a try to this technology. On the other hand, nowadays, Real-time applications and microservices have been spreading very fast, which means the need for this kind of technology will be more important than ever. For example, autonomous vehicles’ technologies are hardly dependent on real-time applications and using this or similar frameworks might be a solution for cutting-edge technologies.

Top companies using Node.js. Many big companies use this technology: Netflix, Linkedin, Walmart, Trello, Uber, Paypal, Medium, eBay, NASA, and so on. For example, Linkedin changed its mobile backend from ruby on rails to node.js. Kiran Prasad, Director of Mobile Engineering at LinkedIn, mentions that node.js was chosen for better performance, fewer servers, and using front-end developer for the back-end.

Languages used. According to 2018 node.js user survey report, developers use other programming languages besides node, largely JavaScript, Python, Java, and PHP. More detailed: JavaScript(93%), Python(37%), Java(35%), PHP(31%), .Net(20%), C++(16%), Go (16%), C (15%), Ruby (14%), Swift (9%).

Important topics of Node.js is that node package manager (npm), modules, socket.io, middlewares, and express.js

2. What is NPM?

As it is understood from the name of NPM (Node Package Manager), it is the node module manager created for saving and using node modules in a commonplace (https://www.npmjs.com/). Over time, it has become available in frontend libraries thanks to tools such as webpack and babel of node modules. Javascript has become available in both browser, server, developer, and desktop applications.

Previously Javascript was only running web pages on the browser with a single library such as Mootools and JQuery. Along with the advancements, there is a need for a “structure” in which many large and small modules can easily be accessed. The need for these modules to be found in an open-source area caused the birth of NPM. And this requirement provided by npm.

In fact, this type of module sharing platform existed in other languages, and it has been used for a long time. For example, we can see the development of package management tools such as npm, NuGet, PyPI, etc. at http://www.modulecounts.com/. Of course, this module count is an important resource in terms of showing the interest in languages even if the numbers and increase do not show the quality of these packages.

Figure 1: Module counts, source: http://www.modulecounts.com/

While developing new generation projects with npm containing over 1 million JS packages, we are dependent on hundreds and thousands of modules, and how we can manage this dependency and their updates. Here, SemVer (Semantic Versioning) comes into play [1] [2].

Thanks to Semantic versioning, it becomes possible to manage the dependencies of so many libraries. For example, the 3 digits in the 1.2.6 version do the following. When using a library, how the changes in that library affect your component.

  • major (breaking): We will need to make some updates to your code when you make an update due to a change in the module interface.
  • minor (feature): Adding a new feature without modifying the module interface.
  • patch versions (fix): If we solve just one mistake and without any changes on the interface.

Figure 2: An example of how versioning works for different stages. Source: npmjs.org

3. Module and module.exports

After defining any object, function, variable with Node.js, we can use the code of module.exports or exports to use the codes written in other files. The keyword module.exports and exports is a global object that can be used within every Node.js file. For example; exporting a variable [3]:

index.js

console.log(“This is the index file”);const message = require(‘./another_file’);console.log(message);

another_file.js

module.exports = “This message from another file!”;

Result:

This is the index fileThis message from another file

Export property

Since the data type of the” exports” keyword is an object, we can add several properties to the exports object. The message property written in the message.js module is exported as the property of the exports object below.

message.js

module.exports.mytext = “Hello Node!”;

index.js

console.log(“This is the index file”);const message = require(‘./message’);console.log(message);

Output:

This is the index file{ hello: ‘Hello Node!’ }

The module returns the { hello: “Hello Node!” } object with the required function and assigns it to the message variable. The message property in the object is reached by message.hello

Export method

Since the data type of the export keyword is an object, we can add various methods to the exports object. The print function written in the posts.js module is exported as the method of the exports object below.

users.js

exports.showUserInfo = function (parameter1) {  console.log(parameter1);}

index.js

console.log(“This is the index file”);const users = require(‘./users’);users.showUserInfo(“My name is Hasan!”);

Output:

This is the index fileMy name is Hasan!

Export function

index.js

console.log(“This is index file”);const users = require(‘./users’);users(“Hasan”, “Gökçe”);

users.js

module.exports = function (name, surname) {  console.log(name + “ “ + surname);}

output:

This is index file

Hasan Gökçe

Export function as a class

Posts.js

module.exports = function (postId, postTitle) {  this.postId = postId;  this.postTitle = postTitle;  this.postInfo = function () {    return this.postId + ‘ ‘ + this.postTitle;  }}

index.js

const Posts = require(‘./Posts’);console.log(“This is index file”);let post = new Posts (23, “This is a post title.”)console.log( post.postInfo() );

Output:

This is index file23 This is a post title

4. Socket.io

Socket.io is in a continuous loop between a browser page and a server running in the background; is a double-sided and event-based library. So let’s consider an HTML page and server, for example, a javascript page. In the events on our browser page, we may want to take a background action instantly or access all users using this page. In this case, we come across a structure that allows us to instantly communicate with the background with a very simple process. Socket.io provides us with a two-way bridge with the server. Of course, this bridge can sometimes break. This is a loop and it will always try to reconnect. For this reason, we call it real-time.

Namespaces can actually be thought of as neighborhoods around the world. Each neighborhood must have its own name. There may be private rooms within these domains. So apartments. These apartments may also have their own names and special messages can be sent to the residents of this apartment. We may want to join this room, ie the apartment, and leave. This channel allows you to send a private message or request. Of course, we don’t have to be connected to a single apartment because you are in this room. We can also send messages to other apartments, the outside world.

5. Middleware

Middleware is intermediate software between applications that communicate with each other to perform repetitive tasks. They do not take action alone. For example, they can provide communication and data management for distributed applications. However, they cannot initiate direct communication or exchange data.

To summarize, a web server can return dynamic web pages in relation to the user’s profile through middleware. Here, the application handles the session/identity management of the user. In a classic web application, the user sends the request and receives a response from the server in return. In an advanced structure, the request is transmitted to the intermediate application. For example, it checks the user’s session and evaluates the information from the server in relation to the user. If the user has not started a session, it redirects them to the login page. Otherwise, control operation would have to be repeatedly performed on each routing operation. This, of course, will both increase the costs and make the application difficult to control. As another example, adding the character set to the response from the server can be considered.

Depending on our short definition, middleware can be created for purposes such as database transactions, transactions between application servers, message controls, and authentication. Structures such as soap, rest, and JSON can be used in the communication of applications. The middleware acts according to all these purposes.

Considering its features, it can be positioned at an intermediate level:

  • Application-level middleware
  • Router-level middleware
  • Error handling middleware
  • Built-in middleware
  • Third-party middleware

Intermediate applications/layers often appear at the application level if they are used for purposes such as login control or log and can interact with each process. Router-level interactions come into play on the basis of the specified URIs.

For example, a web framework Express defines itself as a set of middleware functions, and often tasks such as executing a code, making changes to request and response objects, terminating the request-response loop.

6. Express Framework

Thanks to the Express, which we can install as a package over npm, we can do Url parse and routing more easily, and we can do our static file management works more easily. In short, Expressjs provides us with all the necessary infrastructure to make a website/application with nodejs. It is enough to write npm install express –save to the console to install Express. It will be installed like other packages in Express. Let’s make a small example.

var express=require(‘express’);var app=express();app.get(‘/’, function (req, res) {  res.send(‘Hello World!’)});app.listen(3000,function () {  console.log(‘Server is listening to port 3000!’’)});

Routing is the structure that we have specified how to proceed and where it should be directed according to the incoming Url. It is very easy to do this in the Express Framework. The routing structure in Express works with HTTP methods. The general structure is app.method(URL, CALLBACK). Methods of the HTTP protocol such as GET, POST, PUT, PATCH, and DELETE are used in the method section.

As we know, websites/applications run on the HTTP protocol. When you type the site address in a browser, it goes to the server over HTTP protocol along with any method of HTTP. In this way, operations can be performed on the server according to the URL and HTTP method. The default HTTP Method is the GET method. When we try to enter an address via the browser, the browser uses the GET method by default.

If the incoming URL matches this pattern, the CALLBACK function is executed. The callback function takes two variables. The first one is the variable that we get information about the request and the response. We can change the variable names as we wish. Let’s make an example related to routing.

const express=require(‘express’);const app=express();app.get(‘/’,function (req,res) {  // not implemented yet  res.send(‘Home’);});app.post(‘/’,function (req,res) {  // not implemented yet  res.send(‘Home Post’);});app.get(‘/page1’,function (req,res) {  // not implemented yet  res.send(‘get page 1’);});app.post(‘/post’,function (req,res) {  // not implemented yet  res.send(‘method post’);});app.put(‘/put’,function (req,res) {  // not implemented yet  res.send(‘method put’);});app.delete(‘/delete’,function (req,res) {  // not implemented yet  res.send(‘method delete’);});app.listen(3000,function () {  // not implemented yet  console.log(‘listening to port 3000’)});

If we look at our codes, we first put the express package we installed in the express variable. Then we created an express application named app. We create a route in the next process. We have specified what should happen when ‘/’ is entered on this route as url, that is, when it is left blank. For this, we used the get function of the app application we created. The callback function of the get function takes two variables: req, res. One is the request, that is, the req we manage the request, the other is the response variable, which is the response variable we manage. Within the callback function, we can send information to the user with the send function of the res variable. We sent the article. In the other route process, we look at what should happen when the ‘/ ‘ is entered as the url, but the Http Post method is used. In other route operations, we specify different Http methods and what to do on different URLs. Logic is simple. Choose http method, set url, write callback. That’s the routeing logic in Express. In the last part of our sample code, we ensure that the app express runs from 3000 ports. [4]

var express=require(‘express’);var app=express();app.get(‘/’,function (req,res) {  res.send(‘Home’);});app.all(‘/pegeall’,function (req,res) {  res.send(‘Page All’);});app.get(‘/ab?cd’,function (req,res) {  res.send(‘Page ab?cd!’);});app.get(‘/de+fg’,function (req,res) {  res.send(‘Page de+fg!’);});app.get(‘/hi*jk’,function (req,res) {  res.send(‘Page hi*jk!’);});app.get(‘/page/:variable1/parameter/:variable2’, function(req, res) {  res.send(req.params);});app.listen(3000,function () {console.log(‘listening to port 3000’)});

If we look at our example, it is actually almost the same as the previous example. In the beginning, we created an express application again. Then we defined routes. Then we opened the application over 3000 ports. The difference is in route identification.

The first route definition is the same as in the first example. If we look at the second route definition, the app.all (…) function was used differently. This function shows that this route definition will work with all HTTP methods as long as the URL is provided.

Let’s look at the third route definition. Differently, the expression “/ab?cd” was used in the URL section. The sign indicates that the preceding letter is optional. In other words, if we write in “/abcd” through the browser and write in “/acd”, this route will work again.

Fourth, in the route definition, “/ de+fg” expression was used in the URL section. The meaning of the + sign here means that the letter coming before it can be duplicated as much as it wishes. So if we write in “/defg”, write in “/deeefg” this route will work.

In the fifth routing definition, “/hi*jk” expression was used in the URL section. The * sign here means you can write whatever you want together. In other words, if we write “/hijk”, “/ hi123456jk” means that this route will work.

If we look at the sixth and last route definition, there are two variable definitions in the URL, namely variable1 and variable2. Variable definitions are indicated with a “:” sign before them. Whatever is written to these variables in the URL means that we can access them from within the application. We can access these variables with the params variable of the req variable in the callback function of the route definition. For example, when we write the URL “/page/11/parameter/22” we can access these variables as “req.params.variable1” or “req.params.variable2”.

But most of the big projects have dozens of CSS, js, and image files. Do we have to define routes for each of them? Of course no. The authors of the Express Framework thought about this and wrote the Static Files feature for this.

app.use(express.static(‘public’));app.use(‘/js’,express.static(‘static’));

Conclusion

Node.js and its frameworks and libraries handle numerous works with JavaScript language. This technology reduces development time for an application. The second conclusion, it is relatively a new technology, developers must be careful about security issues.

References

[1] https://docs.npmjs.com/about-semantic-versioning

[2] https://blog.npmjs.org/post/162134793605/why-use-semver

[3] https://nodejs.org/dist/latest-v14.x/docs/api/modules.html

[4] https://expressjs.com/tr/starter/basic-routing.html

--

--