express middleware after response - javascript

I've had a problem with middleware function which is launching on finish execution of main function from endpoint. Here is my middleware:
export const someMiddleware = async (
req: Request,
res: Response,
next: NextFunction
) => {
res.on("finish", () => {
//here
})
next();
}
I am having trouble getting the data that was sent to the client from the request handled by this middleware, can anyone tell me how to get the response body that is sent to the client inside the on () callback?
Thanks for any help!

This is quite painful with Express. One way to handle this is to override the send and write functions, and capture the output this way.
It's not impossible to do this, other middlewares like a gzip middleware would do this too.
A frustration with this limitation has eventually lead me to write my own framework, so I get where you are coming from.

Related

node.js express: Is there a way to cancel http response in middleware?

I am writing a timeout middleware with express in node.js.
app.use((req, res, next) => {
res.setTimeout(3000, () => {
console.warn("Timeout - response end with 408")
res.status(408).json({ "error": "timeout 408" });
// !!! error will happen with next function when call like `res.send()`:
// Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
next()
})
If there's an endpoint that takes more than 3000 ms, my middleware will repsond with 408. However, the next function will respond again. I don't want to check if the response has been already sent by res.headersSent api every time.
Is there a better way to handle this - like the title said - to cancel the next response in the middleware?
It's your own code in the response handler that is still running (probably waiting for some asynchronous operation to complete). There is no way to tell the interpreter to stop running that code from outside that code. Javascript does not have that feature unless you put that code in a WorkerThread or a separate process (in which case you could kill that thread/process).
If you're just trying to suppress that warning when the code eventually tries to send its response (after the timeout response has already been sent), you could do something like this:
app.use((req, res, next) => {
res.setTimeout(3000, () => {
console.warn("Timeout - response end with 408")
res.status(408).json({ "error": "timeout 408" });
// to avoid warnings after a timeout sent,
// replace the send functions with no-ops
// for the rest of this particular response object's lifetime
res.json = res.send = res.sendFile = res.jsonP = res.end = res.sendStatus = function() {
return this;
}
});
next();
});

using stream.pipe make express middleware skipped

im using express and nodejs for my api server,
and now im implementing pdf download (im using pdf-creator-node) for converting html to pdf.
the pdf-creator-node will create a stream when converting a html, and when i pipe it, all my middleware (notFoundHandler, errorHandler,responseLogger) got skipped
router.get(
'/generatePDF', authenticate, schemaValidation({ params: generatePDFschema }),
(req, res, next) => {
generatePDF(details) {
const template = readFile('./src/templates/da-template.html');
const receipt = {
html: template,
data: payload,
type: 'stream'
};
const generatedPdf = pdf.create(receipt, advisOptions);
return generatedPdf;
}
const pdfStream = generatePDF(details);
res.setHeader('Content-type', 'application/pdf');
pdfStream.pipe(res);
},
notFoundHandler,
errorHandler,
responseLogger
);
is there any express api can i use to pipe a stream?
The middleware you show is passed to router.get() AFTER your request handler so it will not get a chance to run unless you call next() in your request handler. When you pass multiple request handlers to a router.get(), they will run sequentially in order and the 2nd one will only get a chance to run if the first one calls next(). Same for the 3rd one, and so on.
Furthermore, pdfStream.pipe(res); does not call next().
I don't know exactly what those middleware functions are supposed to do, but making a guess based on their names, perhaps they are supposed to run BEFORE your request handler, not after so they can put things in place for various error conditions.
If you want further help, then please show the code for those three middleware functions so we can see more specifically what they are trying to do.

How to create a loading animation using "response.send()", then change it to the result of a promise after it is resolved?

I am trying to create a loading animation using "response.send()" (could be response.sendFile() too), and then to change the content of "response.send()" with the results of a promise after it is resolved.
app.get("/image/:id", async (request, response) => {
response.send("loading");
serveImage(request.params.id).then((result) => {
response.send(result);
});
}
I keep getting the following error.
UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]:
Cannot set headers after they are sent to the client
How can I circumvent this?
You can't send more that one response with Express' response.send(). You can call response.write() more than once, but most clients will be waiting for the end of the response before communicating the result back to your code anyway, so unless you have a very special type of client, that probably won't help either.
What you should probably do is to have the client itself put up the loading... when it makes the request and then when it gets the final result, it can take that down and display the result. Make that part of the presentation be controlled by the client itself rather than the server.
Actually you cannot write res.send twice in one route.
For your use case you'll have to use response.write and then response.end for the second call
So you can write like this
app.get("/image/:id", async (request, response) => {
response.write("loading");
serveImage(request.params.id).then((result) => {
response.write(result);
});
response.end();
}

Custom middleware for express routes

I actually implemented a custom middleware in an expressJs application. I aim for modifying the request object before sending it back. It works and the result is exactly what i was expecting, but i am not sure if this is the correct way to do so. I am kind of afraid, that manipulating the reqeust object is not the correct way to do this.
Here is the code:
expressApp.get('/apps/:id', isAuthenticated, appLinks(dbController), async (req, res) => {
res.send(req.__appLink)
})
app-links.ts:
export const appLinks: MiddlewareWrapper = (dbController: DatabaseHandler) => async (req: Request, res: Response, next: NextFunction) => {
dbResult = modifyMyDatabaseResult(await dbController.getApps());
req.__appLink = dbResult
next()
}
As you can see, in my route i send req.__appLink which was set inside the middleware. It this the correct way to do such things?
This is good! Nothing is wrong with modifying the req object.
Yes this is fine. But for better presentation you can save the result of req._appLink in a variable and pass it to res object.

Dangling callbacks: return response before every callback has returned

Question: Would you consider dangling callbacks as bad node.js style or even dangerous? If so under which premise?
Case: as described below, imagine you need to make calls to a DB in an express server that updates some data. Yet the client doesn't need to be informed about the result. In this case you could return a response immediately, not waiting for the asynchronous call to complete. This would be described as dangling callback for lack of a better name.
Why is this interesting?: Because tutorials and documentation in most cases show the case of waiting, in worst cases teaching callback hell. Recall your first experiences with say express, mongodb and passport.
Example:
'use strict'
const assert = require('assert')
const express = require('express')
const app = express()
function longOperation (value, cb) {
// might fail and: return cb(err) ...here
setTimeout(() => {
// after some time invokes the callback
return cb(null, value)
}, 4000)
}
app.get('/ping', function (req, res) {
// do some declartions here
//
// do some request processesing here
// call a long op, such as a DB call here.
// however the client does not need to be
// informed about the result of the operation
longOperation(1, (err, val) => {
assert(!err)
assert(val === 1)
console.log('...fired callback here though')
return
})
console.log('sending response here...')
return res.send('Hello!')
})
let server = app.listen(3000, function () {
console.log('Starting test:')
})
Yeah, this is basically what called a "fire and forget" service in other contexts, and could also be the first step in a good design implementing command-query response separation.
I don't consider it a "dangling callback", the response in this case acknowledges that the request was received. Your best bet here would be to make sure your response includes some kind of hypermedia that lets clients get the status of their request later, and if it's an error they can fix have the content at the new resource URL tell them how.
Think of it in the case of a user registration workflow where the user has to be approved by an admin, or has to confirm their email before getting access.

Categories

Resources