Express: Get the data sent on finish - express

I would like to create and express.use a middleware that gets the data sent from all endpoints and use it for caching. But I am unable to get that data with res.on('finish', cb). Is there even such a thing ?
Thank you

Add middleware and override existing res.send function with your custom function like below
app.use((req, res, next) => {
const { send } = res;
res.send = (data) => {
// Store in cache
return send(data);
};
next();
});

I will close my question since I found a way myself :
app.use((req, res, next) => {
const send = res.send;
res.send = (data) => {
res.send = send; // this line is important not to have an infinite loop
// do something with `data`
return res.send(data);
};
next();
});

Related

Why am I not getting a response from express server?

Sending a logout request to my server but I'm never getting a reply. The logout function is being called and the userID key is being deleted from my redis cache but I never get a response. Here's my code.
export const logout = async (req, res) => {
console.log("logout called");
const { userID } = req.user;
client.del(userID.toString, (err, reply) => {
console.log("inside client.del");
if (err) {
return res.status(500);
} else {
return res.status(200);
}
});
};
Because of callback, you should use promise
export const logout = async (req, res) => {
return new Promise((resolve,reject) => {
console.log("logout called");
const { userID } = req.user;
client.del(userID.toString, (err, reply) => {
console.log("inside client.del");
if (err) {
reject(res.status(500));
} else {
resolve(res.status(200));
}
});
});
}
res.status() does not send a response from the server. All it does is set the status as a property on the response object that will go with some future call that actually sends the response.
It is meant to be used in something like this:
res.status(500).send("Database error");
If you look at the Express doc for res.status(), you will see these examples:
res.status(403).end()
res.status(400).send('Bad Request')
res.status(404).sendFile('/absolute/path/to/404.png')
And, see that they all are followed by some other method that actually causes the response to be sent.
And, if you still had any doubt, you can look in the Express code repository and see this:
res.status = function status(code) {
this.statusCode = code;
return this;
};
Which shows that it's just setting a property on the response object and not actually sending the response yet.
You can use res.sendStatus() instead which will BOTH set the status and send the response:
export const logout = (req, res) => {
console.log("logout called");
const { userID } = req.user;
client.del(userID.toString, (err, reply) => {
console.log("inside client.del");
if (err) {
res.sendStatus(500);
} else {
res.sendStatus(200);
}
});
};
Note, I removed the two return keywords since they don't accomplish anything useful in this particular context.
I also removed the async keyword from the function definition since it was not doing anything useful in this context.

Cleaner way to write api route handlers in NextJS

Currently most of the api route handlers are in the following shape(api/test.js):
export default function handler(req, res) {
if (req.method === 'POST') {
// Process a POST request
} else {
// Handle any other HTTP method
}
}
where we constantly compare req.method with ifs
Is there a way to write it similar to ExpressJS:
app.get(...)
import nextConnect from 'next-connect';
const handler = nextConnect();
//handler.use(middleware);
handler.get(async (req, res) => {
...your code
})
...
handler.post(async (req, res) => {
...your code
})
...
So in theory you can have /api/product where you have .get .post .delete (etc) in 1 api route
Clean solution (/api/product.js)
const handler = async (req, res) => {
try {
}
catch(e){
}
}

Callback function 'next' is executed automatically without making a call to it

I have this POST method which uses FetchURL middleware to fetch data from the url submitted by the user.
router.post('/', FetchURL, (req, res) => {
console.info('data received');
...
})
Everything works with response.ok being true, but the contrary case doesn't quite work as expected.
I don't want next to be called when response.ok equals false.
But I get to see "data received" logged to the console which means the next function does get called on its own.
fetch_url.js
function FetchURL(req, res, next) {
fetch(req.body.input_url)
.then(response => {
if(response.ok)
return response.json();
// else render error message on the client machine
res.status(response.status)
.render('index', {
errStatus: [response.status, response.statusText]
});
/* Throwing an Error here is the only way I could prevent the next callback */
// throw new Error(`Request failed with status code ${response.status}.`);
})
.then(data => {
req.data = data;
next();
})
.catch(err => console.error(err));
}
I could not find anything relevant on the documentation of expressjs middleware. The only way I could prevent next from being called is by throwing an Error on the server.
What happens behind the scene here?
try making a second check before next is called like following
function FetchURL(req, res, next) {
fetch(req.body.input_url)
.then(response => {
if(response.ok) // wrap your response in a temporary object.
return { fail: false, data: response.json() } ;
// else render error message on the client machine
res.status(response.status)
.render('index', {
errStatus: [response.status, response.statusText]
});
/* Instead of throwing an Error, return something indicating error */
return { fail: true };
})
.then(data => {
// check if previous procedure has failed.
if(!data.fail) {
req.data = data.data;
next();
}
})
.catch(err => console.error(err));
}

Axios interceptor use express req object

I have an express route in which I send a header from the front end, in this route I'm making a GET request using axios. I created an interceptor with axios, but I would like to be able to read the req object from the activated route in order to add the header to the axios GET call.
// Example Interceptor
axios.interceptors.request.use(
config => {
// How to get req.headers from the route here?
return config;
},
error => {
return Promise.reject(error);
}
);
// Exemple GET route
router.get('/get', async (req, res, next) => {
try {
const { data } = await axios.get('https://kjhf.fsadjhfewq.....');
} catch (error) {
console.log(error)
}
res.status(200).json({});
});
Is it possible to do this?
So I think the way to do this is to use a middleware to set the headers, and pass on the axios instance
// apiSetHeader.js middleware
exports.default = (req, res, next) => {
req.CustomAxios = axios.create({
headers: { 'HeaderForTheApi': req.headers.apiHeader'}
})
next()
}
And then use that in your route
// Exemple GET route
router.get('/get', apiSetHeaderMiddleware, async (req, res, next) => {
try {
const { data } = await req.CustomAxios.get('https://kjhf.fsadjhfewq.....');
} catch (error) {
console.log(error)
}
res.status(200).json({});
});
Hope this helps!

Problem with interrogation my API with mongoose

I have a problem with the result of my query at the database mongoDB.
When I exec my query the result is always empty: [].
I'm new user, please help me.
I use SO Mac OS Catalina.
This code is in the access of my API (I obscured my password)
//connection on mongoDB
let URI =
"mongodb+srv://marco:<xxxxxxxxx>#persona-iydyz.gcp.mongodb.net/test?retryWrites=true&w=majority";
mongoose.connect(URI,
{ useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.on('connected', () => {console.log('mongodb connected')})
and this code is in my route who exec the query
var express = require('express');
var router = express.Router();
const persona = require('./../classes/persona')
/* GET home page. */
router.get('/', function(req, res, next) {
let result = persona.find().exec();
res.send(result);
});
module.exports = router;
I don't understand why my result is always empty.
please help me. Thanks
Any mongoose model method should be called with a callback, otherwise it just builds a query, not executes it. exec() is there to execute this built query. You can use callback directly if you do not have to do something with built query.
Then try with the below code:
router.get('/', function(req, res, next) {
persona.find({}, (err, result) => {
if(err)
return res.send(err.message);
return res.send(result)
})
});
If you are using promisified mongoose, then it will be
router.get('/', function(req, res, next) {
try {
let result = await persona.find({});
return res.send(result);
} catch(err) {
return res.send(err.message);
}
});
P.S. Check is the mongoDb is connected successfully or not!