Express is a popular web framework for Node.js, it can simplify and accelerate development. If you're already using Node.js for your web application, you may consider migrating to Express if you find that your current setup lacks the necessary features, structure, or ease of development that Express provides such as routing, middleware and template engine support. In this topic, we start with a simple Node.js server that handles routes and operations using the built-in http module. Then, we migrate it to use Express which simplifies routing and request handling, making the code more concise and maintainable.
Node server
Let's import the necessary modules first, then we define the hostname and port on which the server will listen for incoming requests:
// Import required modules
import { createServer } from 'http';
import { parse, resolve } from 'url';
// Define the server hostname and port
const hostname = 'localhost';
const port = 3000;Next, we create the HTTP server and parse the request URL:
// Create the server
const server = createServer((req, res) => {
// Parse the request URL
const parsedUrl = parse(req.url, true);
const path = parsedUrl.pathname;
// Request handling logic goes next
});After that, we can define the routes and corresponding operations:
... {
// Define the routes and corresponding operations
const routes = {
'/': (req, res) => {
// Logic for handling the root route
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, World!');
},
'/about': (req, res) => {
// Logic for handling the "/about" route
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('About page');
},
'/contact': (req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Contact page');
},
'/api/data': (req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
const data = { message: 'This is some data from the API' };
res.end(JSON.stringify(data));
},
// Handle 404 Not Found
'default': (req, res) => {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('404 Not Found');
}
};
});After setting up the routes, we find the appropriate route handler or use the default handler:
...
// Find the appropriate route handler or use the default handler
const routeHandler = routes[path] || routes['default'];
routeHandler(req, res);
});This code determines the appropriate route handler function based on the path extracted from the request URL. If a matching route handler is found, it is executed, passing in the req and res objects. If no matching route handler is found, a default handler is used to handle 404 Not Found errors.
Lastly, we start the server:
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});Now let's migrate this to Express.
Express server
Install express with npm:
npm install expressFirst, we need to import Express and create an instance of it:
// Import required modules
import express from 'express';
// Create an instance of Express
const app = express();
const port = 3000;
const hostname = 'localhost';We import the express module and create an instance of the Express application by invoking the express() function. This instance represents our server.
Next, we define routes and corresponding operations using the Express app object:
// Define the routes and corresponding operations
app.get('/', (req, res) => {
res.status(200).set('Content-Type', 'text/plain').send('Hello, World!');
});
app.get('/about', (req, res) => {
res.status(200).set('Content-Type', 'text/plain').send('About page');
});
app.get('/contact', (req, res) => {
res.status(200).set('Content-Type', 'text/plain').send('Contact page');
});
app.get('/api/data', (req, res) => {
const data = { message: 'This is some data from the API' };
res.status(200).set('Content-Type', 'application/json').json(data);
});We use the app.get() method to define routes and their corresponding handler functions. In this example, we define handlers for the root route '/' and the '/about' route. The handler functions take the req (request) and res (response) objects as parameters, allowing us to handle the request and send back a response.
We can also define a 404 Not Found error handler:
// Handle 404 Not Found
app.use((req, res) => {
res.status(404).set('Content-Type', 'text/plain').send('404 Not Found');
});We use the app.use() method to define a middleware function that will be executed for any request that doesn't match the defined routes. In this case, we set the response status code to 404 and send a simple error message.
Lastly, we can start the server:
// Start the server
app.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});We use the app.listen() method to start the server and make it listen on the specified port. The optional callback function is executed once the server starts. This example logs a message indicating that the server is running.
By using Express, we can define routes and their handlers using a more intuitive and concise API. Express takes care of the underlying HTTP server setup and request handling, allowing us to focus on defining the routes and their corresponding operations.
Here's the result of the Express server:
Express to the rescue
As you can see from the examples above while it's possible to do the tasks that was needed with just Node.js, using Express made things simpler.
Routing: In Node.js, you would have to manually parse URLs and handle different HTTP methods (GET, POST, etc.) to set up routing. As you can see from our example Express provides a way that is requires less code to create a server and setup routes.
JSON and URL-encoded Form Data: Express.js has built-in middleware for parsing JSON and URL-encoded form data. In Node.js, you would have to manually parse these types of data from the request body.
Middleware: Express.js has built-in support for middleware. Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. This makes it easy to insert custom functionality into your application, like logging, error handling, or user authentication. We used it to handle the handle the not found content (404).
Here are a few other things that are harder to do with Node.js alone, but made easier with Express.js:
Template Engines: Express.js supports many template engines, which makes it easy to generate HTML (or other types of documents) on the server side. Node.js doesn't have built-in support for template engines.
Error Handling: Express.js has a built-in error handling mechanism. In Node.js, you would have to manually write a lot of try/catch blocks and error handling code.
Serving Static Files: Express.js makes it easy to serve static files like images, CSS files, and JavaScript files. In Node.js, you would have to manually set up routes and file reading operations to serve static files.
Conclusion
Ultimately, the decision to migrate from Node.js to Express depends on your specific needs and the current limitations you're facing. If you're already using Node.js and want to take advantage of a robust web application framework, Express is a popular choice that can simplify development and provide additional features and community support. In the migrated version, we use the Express framework to create an instance of the server and define the routes using the app.get() method for GET requests. We set the appropriate status codes and response headers, and use the res.send() or res.json() methods to send the response data. The app.use() method is used to handle any requests that don't match the defined routes, serving a 404 Not Found response.