I have a utility file which basically has two functions (one to detect user location and another to get user device details) acting as middlewares. Now I would like to know whether it is possible to combine both the middlewares together as one so that it could be used with other middlewares on the route. I would also like to have the freedom of using the functions in the utility file individually when required.
Utility file
const axios = require("axios");
const requestIp = require("request-ip");
const getDeviceLocation = async (req, res, next) => {
try {
// ToDO: Check if it works on production
const clientIp = requestIp.getClientIp(req);
const ipToCheck = clientIp === "::1" || "127.0.0.1" ? "" : clientIp;
const details = await axios.get("https://geoip-db.com/json/" + ipToCheck);
// Attach returned results to the request body
req.body.country = details.data.country_name;
req.body.state = details.data.state;
req.body.city = details.data.city;
// Run next middleware
next();
}
catch(error) {
return res.status(500).json({ message: "ERROR_OCCURRED" });
}
};
const getDeviceClient = async (req, res, next) => {
const userAgent = req.headers["user-agent"];
console.log("Device UA: " + userAgent);
next();
};
module.exports = { getDeviceLocation, getDeviceClient };
Example Routes
app.post("/v1/register", [getDeviceLocation, getDeviceClient, Otp.verify], User.create);
app.post("/v1/auth/google", [getDeviceLocation, getDeviceClient, Auth.verifyGoogleIdToken], Auth.useGoogle);
I would like to have getDeviceLocation
and getDeviceClient
combined into one say getDeviceInfo
yet have the freedom to use getDeviceLocation
and getDeviceClient
individually when required on any route.
Middleware has the ability to modify the req and res objects, run any code you wish, end the request and response cycle, and move onto the following functions. Note the order of your middleware, as invoking the next () function is required in each preceding middleware.
All middleware functions in Express.js accept three arguments following the request, response, and next lifecycle methods. In your index.js file, define a function with the three lifecycle methods as arguments: function myCustomMiddleware( req, res, next) { // ... }
Or we can create a middleware for saving, which will do the following: Whenever a save request arrives, call Product/User server's save and Search server's save. If the first save fails, do not call the save on other one (this keeps the databases consistent). Let's look at the design diagrams without and with a middleware.
Middleware speeds development of distributed applications by simplifying connectivity between applications, application components and back-end data sources. What is middleware? Middleware is software that enables one or more kinds of communication or connectivity between two or more applications or application components in a distributed network.
Express allows you to declare middleware in an array, so you can simply define an array of the middlewares you'd like to combine:
const getDeviceLocation = async (req, res, next) => {
...
};
const getDeviceClient = async (req, res, next) => {
...
};
const getDeviceInfo = [getDeviceLocation, getDeviceClient];
module.exports = { getDeviceLocation, getDeviceClient, getDeviceInfo };
You can then use any combination of one or both of the middleware wherever you like:
app.use('/foo', getDeviceLocation, () => {});
app.use('/bar', getDeviceClient, () => {});
app.use('/baz', getDeviceInfo, () => {});
In your case maybe you can use something simple like this
const getDeviceInfo = async (req, res, next) => {
await getDeviceClient(req, res, async () => {
await getDeviceLocation(req, res, next)
})
}
But you may need to handle error cases.
If you'd like to avoid callback hells you can use something like this:
const nextInterceptor = error => {
if (error) { throw error; }
};
const combineMiddlewares = middlewares => (req, res, next) => (
middlewares.reduce((previousMiddleware, currentMiddleware) => (
previousMiddleware.then(() => currentMiddleware(req, res, nextInterceptor))
), Promise.resolve())
.then(() => next())
.catch(next)
);
const commonMiddlewares = combineMiddlewares([getDeviceLocation, getDeviceClient]);
app.post("/v1/register", [commonMiddlewares, Otp.verify], User.create);
app.post("/v1/auth/google", [commonMiddlewares, Auth.verifyGoogleIdToken], Auth.useGoogle);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With