In the vast landscape of web development, Node.js stands tall as a powerful and event-driven server, efficiently managing server connections with its single-threaded prowess. It navigates the complexities of seamlessly processing each request within the callback, ensuring a smooth and responsive server.
Explore the nuances of Node.js and compare it with Java & .NET.
Yet, as any developer knows, handling a myriad of requests in a busy application can present challenges. That is, despite its skills, Node.js may face challenges in efficiently managing all these requests.
To tackle this problem, comes Express.js — a silent hero among web application frameworks for Node.js. It’s not just a solution; Express.js is a powerful toolkit that elevates the development process.
So, whether you’re a seasoned developer or new to web development, this blog guides you through Express.js, covering installation, building robust servers, mastering routing, grasping middleware, and more.
Let ‘s get started!
What is Express.js and why is it preferred?
Express.js is a robust web application framework for Node.js, offering extensive features for building web and mobile applications. Serving as a layer on top of Node.js, it facilitates the management of servers and routes. It is loved for being speedy, flexible, and minimalist, giving developers the freedom and control they crave over their apps.
It is popular because of these reasons:
- Supports Model-View-Controller (MVC) architecture for versatile web app design.
- Leverages Node.js’ single-threaded and asynchronous model for efficiency.
- Cross-platform compatibility.
Excited to get started? Let’s install Express.js first!
Installing Express.js
Quick Note: Before delving into Express, ensure Node.js is installed on your operating system.
Follow these steps to set up your Express application:
Step 1: Create a directory to run your application with this code:
mkdir Demo cd Demo
Step 2: Use NPM to create the package.json file:
npm init --y
Note: You can use –y to quickly set default settings in the Package.json file, which you can modify later.
Step 3: Install Express.js locally:
npm install --save express
Note: Use “save” to install this package within the dependencies section.
The project’s structure will be as follows:
Your package.json file should resemble the following:
{ "name": "Demo", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon app.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "nodemon": "^3.0.1" }, "dependencies": { "express": "^4.18.2" } }
Congrats! You’ve successfully installed Express.js.
Remember: A server is crucial to facilitate communication between clients and applications. So, up next, I’ll help you build a server with Express.js.
How to build a server with Express.js?
To build a server, we installed Express framework and created a simple server application.
Step 1: Now, we will create the file, app.js, at the root of our project’s directory:
const express = require('express'); const app = express(); app.get('/', (req, res) => res.send('Hello World!')); app.listen(3000, () => console.log('Example app listening on port 3000!'));
Step 2: To initiate the server, open your terminal and enter the following command:
node app.js
Step 3: Initiate the server on port 3000, responding with “Hello World” to http://localhost:3000 upon browser request.
The code begins by requiring the Express module, including npm packages in the project.
Before using Express, define an instance (‘app’) to manage server-client interactions.
Step 4: Employ ‘app.get()’ to specify actions for incoming GET requests, utilizing ‘req’ and ‘res’ objects provided by the Express framework. This approach ensures efficient communication and organized handling of server responses.
Now that you’ve made a server, let’s understand two important terms:
- Routing
- Middleware
Let me explain why Express.js needs them to work well next.
1. Routing in Express.js
1.1. What is Routing?
Routing is like guiding a server on how to react when someone asks for something specific. It involves a path (like ‘/books’) and a method (like GET, PUT, POST, DELETE, etc.) in a web address.
To define the routes, refer below syntax:
app.METHOD(PATH?, HANDLER)
Routers in Express help organize code by keeping related parts in separate files. You can export and import these routes easily. This makes code more manageable.
Quick Note: In Express.js, define all routes before calling app.listen(). Typically, app.listen() is the final function executed in an Express application.
1.2. Routing Method
In web talk, HTTP is like a messenger service between clients and servers. Each route needs a handler function, deciding how the server responds. Here’s a simple example:
// GET method route app.get('/', (req, res) => { res.send('Hello World!')});
Here, when someone requests the main page (‘/’), the server sends back a simple message, like saying ‘Hello World!’
1.3. Routing Path
Think of a routing path as a way to tell the server where clients can ask for things. For instance:
// Home page route app.get('/home', (req, res) => { res.send('Home Page'); });
// About page route app.get('/about', (req, res) => { res.send('About'); });
In the provided code, there are two endpoints, ‘/home’ and ‘/about.’ If a client requests ‘/home,’ it gets ‘Home Page’; for ‘/about,’ it gets ‘About Page.’ The default route runs on ‘/’.
1.4. Routing Parameters
Route parameters are placeholders in the URL that capture specified values. In this case, we use the req.params object, which grants access to all parameters passed in the URL.
app.get('/books/:bookId', (req, res) => { res.send(req.params); });
In the provided source code, the client’s request URL will be:
http://localhost:3000/books/23
Route parameter names should consist of characters ([A-Za-z0-9_]). In our application, a common use of routing parameters is for creating a 404 route.
// For invalid routes app.get('*', (req, res) => { res.send('404! This is an invalid URL.'); });
Now, if we start the server by typing “node app.js” in the command line and visit the URL http://localhost:3000/abcd, the server will respond with a 404 message.
Onwards to understanding Middleware!
2. Middleware functions
Middleware functions in Express have access to the request object, response object, and the next function in the request-response cycle.
Middleware functions in Express are like checkpoints. They modify requests and responses, add headers, and can end or continue the cycle. If a middleware doesn’t end it, it calls next() for the next middleware. Else the request will be left hanging.
Given below is an image that shows how middleware handles client requests and generates the desired responses:
Express.js uses middleware to process incoming requests through a series of functions. Unlike a single handler, it allows multiple functions to be added, enabling modular code and easy integration of third-party packages.
To deepen our understanding, let’s craft a custom middleware function. Consider the following code as an illustration:
const express = require('express'); const app = express(); // Simple request time logger app.use((req, res, next) => { console.log("A new request received at " + Date.now()); // This function call tells that more processing is // required for the current request and is in the next middleware function/route handler. next(); }); app.get('/home', (req, res) => { res.send('Home Page'); }); app.get('/about', (req, res) => { res.send('About Page'); }); app.listen(3000, () => console.log('Example app listening on port 3000!'));
2.1: Setting up Middleware
To configure middleware, be it custom or from an npm module, utilize the app.use() function. It requires a mandatory callback parameter and an optional path parameter, which we omit in our case.
app.use((req, res, next) => { console.log('A new request received at ' + Date.now()); next(); });
The next() function, supplied by Express.js, must be executed within the middleware to allow the request to proceed to the subsequent middleware. This middleware is invoked for each client request. When the server runs, you’ll observe messages in the terminal for every browser request at the / endpoint, like:
A new request received at 1467267512545
2.2: Usage of Middleware functions
Middleware functions can be used for a specific route. See the example below:
const express = require('express'); const app = express(); //Simple request time logger for a specific route app.use('/home', (req, res, next) => { console.log('A new request received at ' + Date.now()); next(); }); app.get('/home', (req, res) => { res.send('Home Page'); }); app.get('/about', (req, res) => { res.send('About Page'); }); app.listen(3000, () => console.log('Example app listening on port 3000!'));
In our example, the arrangement of middleware functions dictates their execution sequence. If we define the route app.get(‘/home’) before the middleware app.use(‘/home’), the middleware function won’t be invoked.”
Did you know?
Understanding the intricacies of your project’s architecture is a fundamental practice for effectively structuring your Express.js application. While it may be considered optional, adhering to a well-defined structure is highly advisable for optimal results.
Up next, you’ll grasp the concept!
Project Structure of an Express App
Here’s a standard structure for an Express-based web application:
project-root/ node_modules/ // This is where the packages installed are stored config/ db.js // Database connection and configuration credentials.js // Passwords/API keys for external services used by your app config.js // Environment variables models/ // For mongoose schemas books.js things.js routes/ // All routes for different entities in different files books.js things.js views/ index.pug 404.pug ... public/ // All static files images/ css/ javascript/ app.js routes.js // Require all routes in this and then require this file in app.js Package.json
This pattern is called MVC, short for model-view-controller. It separates the database model, application UI, and controllers (routes) into distinct files. This design pattern ensures easy scalability for adding more routes or static files in the future, making the code more maintainable.
To sum up, skillfully using middleware functions gives developers a strong set of tools to easily add extra features, making a web app more secure and functional.
The ability to register multiple middleware functions and the adoption of a robust error-handling approach not only facilitates the smooth integration of diverse functionalities but also empowers developers to craft resilient and reliable applications.
So, to elevate your software business, connect with us at Nitor Infotech. We specialize in solving tech problems with cutting-edge solutions.