Built-in Middleware
Built-in Middleware: Express provides built-in middleware functions that offer various functionalities, such as serving static files, parsing request bodies, and more. Example: Serving static files const express = require(‘express’);const app = express(); // Built-in middleware for serving static filesapp.use(express.static(‘public’)); app.listen(3000, () => {console.log(‘Server is running on port 3000’);});
Error-handling Middleware
Error-handling Middleware: Error-handling middleware is used to handle errors that occur during the request-response cycle. It’s defined using middleware functions with four parameters (err, req, res, next) and is typically placed at the end of the middleware chain. Example: Error-handling middleware const express = require(‘express’);const app = express(); app.get(‘/’, (req, res) => {throw new Error(‘An error occurred’);}); // Error-handling middlewareapp.use((err, req, res, next) => {console.error(err.stack);res.status(500).send(‘Something went wrong!’);}); app.listen(3000, () => {console.log(‘Server is running on port 3000’);});
Router-level Middleware
Router-level Middleware: Router-level middleware is applied to specific routes using the router.use() method. It is useful for tasks related to specific routes, like authentication or data validation. Example: Authentication middleware for a specific route const express = require(‘express’);const app = express();const router = express.Router(); // Router-level middlewareconst authenticate = (req, res, next) => {if (req.query.auth === ‘secret’) {next();} else {res.status(401).send(‘Unauthorized’);}}; router.use(authenticate); router.get(‘/’, (req, res) => {res.send(‘Authenticated Route’);}); app.use(‘/auth’, router); app.listen(3000, () => {console.log(‘Server is running on port 3000’);});
Application-level Middleware
Application-level Middleware: Application-level middleware is bound to the entire Express application. It is defined using app.use() or related methods and is executed for every incoming request. It’s suitable for tasks like logging, setting headers, and general pre-processing. Example: Logging middleware const express = require(‘express’);const app = express(); // Application-level middlewareapp.use((req, res, next) => {console.log(Received ${req.method} request at ${req.url});next();}); app.get(‘/’, (req, res) => {res.send(‘Hello, Express!’);}); app.listen(3000, () => {console.log(‘Server is running on port 3000’);});
Middleware & Configurable middleware
If you need your middleware to be configurable, export a function which accepts an options object or other parameters, which, then returns the middleware implementation based on the input parameters. Middleware in Express: Middleware in Express are functions that have access to the request (req), response (res), and the next function in the application’s request-response cycle. They can modify the request and response objects, end the request-response cycle, or call the next middleware in the stack. Middleware is often used for tasks like logging, authentication, validation, and more. Here’s a simple example of a middleware that logs the request method and URL: const express = require(‘express’);const app = express(); // Custom middlewareapp.use((req, res, next) => {console.log(Received ${req.method} request at ${req.url});next(); // Call the next middleware}); app.get(‘/’, (req, res) => {res.send(‘Hello, Express!’);}); app.listen(3000, () => {console.log(‘Server is running on port 3000′);}); In this example, the custom middleware logs the request information before passing the control to the next middleware or route handler using the next() function. Configurable Middleware in Express: Configurable middleware allows you to create middleware functions that can accept parameters during their initialization. This enables you to create more flexible and reusable middleware that can be customized based on specific needs. Here’s an example of configurable middleware that accepts a message parameter: const express = require(‘express’);const app = express(); // Configurable middlewareconst messageMiddleware = (message) => {return (req, res, next) => {console.log(message);next();};}; app.use(messageMiddleware(‘This is a custom message’)); app.get(‘/’, (req, res) => {res.send(‘Hello, Express!’);}); app.listen(3000, () => {console.log(‘Server is running on port 3000′);}); In this example, the messageMiddleware function returns a middleware function that logs the custom message provided during its initialization. This allows you to create multiple instances of the same middleware with different messages. You can further enhance configurable middleware by accepting additional parameters such as configuration objects, database connections, or authentication settings to make them even more versatile. Both middleware and configurable middleware are powerful tools in Express that enable you to modularize your application’s logic, keep your codebase organized, and implement cross-cutting concerns effectively. TYPES OF MIDDLEWARES: These types of middleware are fundamental to Express applications, enabling you to handle various aspects of the request-response cycle efficiently and modularly.
Middleware Overview
Overview Middleware functions are functions that have access to the request object (req), the response object (res), and the next function in the application’s request-response cycle. The next function is a function in the Express router which, when invoked, executes the middleware succeeding the current middleware. Middleware functions can perform the following tasks: If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging. Example Here is an example of a simple “Hello World” Express application. The remainder of this article will define and add three middleware functions to the application: one called myLogger that prints a simple log message, one called requestTime that displays the timestamp of the HTTP request, and one called validateCookies that validates incoming cookies. Middleware function myLogger Here is a simple example of a middleware function called “myLogger”. This function just prints “LOGGED” when a request to the app passes through it. The middleware function is assigned to a variable named myLogger.
app.route() & Express Router
You can create chainable route handlers for a route path by using app.route(). Because the path is specified at a single location, creating modular routes is helpful, as is reducing redundancy and typos Here is an example of chained route handlers that are defined by using app.route(). express.Router Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”. The following example creates a router as a module, loads a middleware function in it, defines some routes, and mounts the router module on a path in the main app. Create a router file named birds.js in the app directory, with the following content: Then, load the router module in the app:
Route handlers
You can provide multiple callback functions that behave like middleware to handle a request. The only exception is that these callbacks might invoke next(‘route’) to bypass the remaining route callbacks. You can use this mechanism to impose pre-conditions on a route, then pass control to subsequent routes if there’s no reason to proceed with the current route. Route handlers can be in the form of a function, an array of functions, or combinations of both, as shown in the following examples. A single callback function can handle a route. For example: More than one callback function can handle a route (make sure you specify the next object). For example: An array of callback functions can handle a route. For example: A combination of independent functions and arrays of functions can handle a route. For example: Response methods The methods on the response object (res) in the following table can send a response to the client, and terminate the request-response cycle. If none of these methods are called from a route handler, the client request will be left hanging. Method Description res.download() Prompt a file to be downloaded. res.end() End the response process. res.json() Send a JSON response. res.jsonp() Send a JSON response with JSONP support. res.redirect() Redirect a request. res.render() Render a view template. res.send() Send a response of various types. res.sendFile() Send a file as an octet stream. res.sendStatus() Set the response status code and send its string representation as the response body.
Route parameters
Route parameters are named URL segments that are used to capture the values specified at their position in the URL. The captured values are populated in the req.params object, with the name of the route parameter specified in the path as their respective keys. Route path: /users/:userId/books/:bookId Request URL: http://localhost:3000/users/34/books/8989 req.params: { “userId”: “34”, “bookId”: “8989” } To define routes with route parameters, simply specify the route parameters in the path of the route as shown below. app.get(‘/users/:userId/books/:bookId’, (req, res) => { res.send(req.params) })
Routing in Express
Routing refers to how an application’s endpoints (URIs) respond to client requests. You define routing using methods of the Express app object that correspond to HTTP methods; for example, app.get() to handle GET requests and app.post to handle POST requests. These routing methods specify a callback function (sometimes called “handler functions”) called when the application receives a request to the specified route (endpoint) and HTTP method. In other words, the application “listens” for requests that match the specified route(s) and method(s), and when it detects a match, it calls the specified callback function. In fact, the routing methods can have more than one callback function as arguments. With multiple callback functions, it is important to provide next as an argument to the callback function and then call next() within the body of the function to hand off control to the next callback. The following code is an example of a very basic route. const express = require(‘express’) const app = express() // respond with “hello world” when a GET request is made to the homepage app.get(‘/’, (req, res) => { res.send(‘hello world’) }) Route methods A route method is derived from one of the HTTP methods, and is attached to an instance of the express class. The following code is an example of routes that are defined for the GET and the POST methods to the root of the app. // GET method route app.get(‘/’, (req, res) => { res.send(‘GET request to the homepage’) }) // POST method route app.post(‘/’, (req, res) => { res.send(‘POST request to the homepage’) }) Express supports methods that correspond to all HTTP request methods: get, post, and so on. For a full list, see app.METHOD. There is a special routing method, app.all(), used to load middleware functions at a path for all HTTP request methods. For example, the following handler is executed for requests to the route “/secret” whether using GET, POST, PUT, DELETE, or any other HTTP request method supported in the http module. app.all(‘/secret’, (req, res, next) => { console.log(‘Accessing the secret section …’) next() // pass control to the next handler })