Node.js and Express server as seen by a Java developer
Introduction
This post is about Node.js basics, mainly from a pragmatic point of view. The majority of TOPdesk developers have a Java background (I previously focused on backend), but during the development of my latest project my team decided to use Node.js. We have surprisingly positive feelings about it, and we think it is worth sharing our experiences.
1. Node.js. What’s that?
Node.js is a platform:
- It’s a JavaScript runtime environment. Assuming that Node.js is installed, it will execute my-code.js:
node my-code.js
- It has core modules (i.e. JavaScript packages) available for your code as imports. For example:
fs
for filesystem,http
for handling requests-responses etc.
Isn’t it analogous to JVM?
If you are very interested in Node.js, you can find more advanced topics later in this post, such as the event loop, non-blocking I/O and asynchronous programming. For now, let’s get back to the basics.
2. npm (Node Package Manager) – Basics
- Npm provides a command line tool to install Node.js packages.
- Dependencies with version numbers are listed in a file called package.json.
- Npm also has a registry on the internet where the published packages are available.
Isn’t it analogous to Maven?
Npm can be used natively with Node.js, but it also has a Maven plugin (packaged together with Node.js) making it possible to bundle it into your Java application.
3. Express server
This is a Node.js based HTTP server. You just import it as a module and add one line of code to listen to HTTP requests on any port you want. In your code, you map URL paths to different functions to be invoked when the incoming path matches. Express builds up a routing table based on your mapping code, and invokes the mapped function by passing the request data (query strings, form data etc.) to it. While your function is preparing the response, it can do networking, I/O operations etc.; so everything you expect from a considerable programming language and runtime environment. After processing, another one-liner is called to pass the processed data (web page, JSON content etc.) to the response. The rest – i.e. sending back the response on HTTP to the client – is done by Express and Node.js.
Isn’t it analogous to Jetty?
Here is a simple example that will run an HTTP server:
var express = require('express');
var app = express();
app.get('/welcome/:name', function(req, res) {
res.send('Welcome ' + req.params.name);
});
app.listen(8081);
[server.js]
Express makes parameters in the path available as a JavaScript variable (:name
→ req.params.name
). A few features of Express routing:
- It makes it possible to add regexp in the path:
app.get('/ab*cd', ...)
- It handles different HTTP methods:
app.put
,app.delete
etc. - Easy implementation of static files serving:
app.use(express.static('public'))
.
3.1. Express server at TOPdesk
Express server serves as a REST container once the RESTful endpoints and routing rules are provided. But don’t forget about securing the calls on the server side, i.e. authorizing the user.
My project is frontend heavy, and so we use Node.js and Express only as a web server for the client side. The TOPdesk Application Server acts as the backend (business logic and data). In our case we don’t do anything with authorization, but in return the server side routing capabilities of Express are not leveraged.
We use the following routings:
- REST API calls to the TOPdesk Application Server system.
- Static file serving (images).
- Responding with the same index.html for any other request. This is a single page application: index.html is loaded only once, so pages are not reloaded. Later, client side routing of Vue.js will update the GUI by loading the proper component. Furthermore, Vue.js keeps components in sync with an inner state.
4. How to set up an application from scratch. A working example
The good news is that setting it up is very simple.
- Install Node.js on your pc (this will install npm as well).
- Create an empty project with a package.json: npm init.
- Add express node module to package.json:
npm install express --save
. - Add server.js to src (copy content from 3. Express server).
- Start your server:
node server.js
.
It will be available on http://localhost:8081/welcome/Dear%20Reader in your browser.
Note that there are many scaffolding possibilities in the form of node modules like express-generator etc. to create a project structure according to your needs.
5. Evaluation (my opinion)
- It’s time to bury the thought that JavaScript is just for playing with the browser GUI.
“Node made JavaScript a viable alternative for server-side programming.”
[Source: Colin Ihrig and Adam Bretz: Full Stack JavaScript Development with MEAN (Sitepoint)]
- There are 450,000 modules available in the npm registry. This is more than in Maven:
[Source: http://www.modulecounts.com/]
- The main criticism of Java developers is valid: JavaScript language is not strongly typed. See its obvious benefit: its flexibility.
- The code you write is concise; there is not much boilerplate.
Conclusions: Node.js at TOPdesk:
- JavaScript is convenient for implementing a strong frontend with a Service Oriented Architecture, with a TOPdesk Application Server as backend (via its REST API). MongoDB is easy to add to the project (just like Express) once you need to store frontend state persistently.
- A common mistake with structuring the code is letting the business logic flow into frontend code. Keep them separated. Let a properly designed REST API be the boundary between the frontend and the backend layers. Note that Node.js makes the code running on the server side also available for the client. This kind of “blending” is ok for some use-cases like validations, weekend check in a calendar etc.
- Be open to using pure JavaScript stack for your frontend: don’t package your JavaScript into a jar file just to make it runnable on a Java based server if you don’t want to make use of the capabilities of Java. Besides, it’s not that much fun to fight with the Node.js Maven plugins.
+1: Node.js advanced (advanced for a Java developer like me).
The strength of Node.js is – besides its ease of use – its performance when the application is I/O intensive or network intensive. Performance measurements and comparisons are out of the scope of this post. I just want to say a few words about how it works inside, and why you always bump into terms like “event loop”, “single threaded” and “asynchronous non-blocking I/O” when googling for Node.js related technicalities.
The event loop running in one single thread
Node.js and JavaScript handle threads quite differently from Java, which is optimal for an average web application (although suboptimal for a mathematical algorithm). The so called event loop resides inside the Node.js engine, and loops continuously, waiting for the incoming events (operations) in a dedicated queue. This is one single thread.
[Source: http://uiandwe.tistory.com/category/N…B%9E%80%3F]
Asynchronous programming and the non-blocking I/O
Extremely slow operations can and should be outsourced from the event loop by asynchronous programming. To decide which operations count as extremely slow, check out the following figure. It shows a comparison of the cost of different I/O operations:
L1 cache: | 3 cycles |
L2 cache: | 14 cycles |
RAM: | 250 cycles |
Disk: | 41,000,000 cycles |
Network: | 240,000,000 cycles |
[Source: http://www.cnoug.net/20100601.html]
If you call a slow function asynchronously, then the event loop gets the work done on an external line (e.g. disk or network). This prevents it from blocking the CPU, which in turn is freed up to handle the next operation in the queue. We refer to this as the non-blocking I/O. The slow operations are running outside the event loop served by a thread pool and the fast ones are running inside, always in the same thread. No time is wasted with opening and closing threads unnecessarily. Once the slow operation is finished, the execution is passed back to Node.js (the event loop in the CPU). In practice the programmer implements this by callbacks, promises and event emitters.
The importance of asynchronous programming
The application developer needs to know how to program asynchronously to leverage its capabilities. If the code overuses synchronous calls, then slow operations keep running in the event loop, blocking everything else in the queue and resulting in a slow application.