Difference between response.status() vs. response.sendStatus() in express - node.js

What is the difference between response.status() and response.sendStatus() in Express.
I notice that one is used generally for post, get, and other middleware, while the later is used in delete requests. Why is this?

status() sets a HTTP status on the response (as a Javascript object on the server side).
sendStatus() sets the status and sends it to the client.
The usage doesn't depend on the HTTP method of the request. In most cases you would use sendStatus anyway since it's unlikely that the status changes once the request is processed (especially since status code is the first line in a raw HTTP response).
Read more in the docs:
https://expressjs.com/en/4x/api.html#res.sendStatus

res.sendStatus is shorthand for implementing res.send and res.status
the link shared by #freakish explains it all.
res.sendStatus(200); // equivalent to res.status(200).send('OK')
res.sendStatus(403); // equivalent to res.status(403).send('Forbidden')
res.sendStatus(404); // equivalent to res.status(404).send('Not Found')
res.sendStatus(500); // equivalent to res.status(500).send('Internal Server Error')

As freakish already pointed out, sendStatus sets and sends the status.
This means that if you want to both set a status and send a body you have to use status. For example, you want to set an error status, and send a body with a JSON that explains why the error occured, you first have to set the status (using status), and then send the JSON (using send). If you had already set the status with sendStatus, it is no longer possible to send the JSON, because you already used a form of sent.

sendStatus(code) is a function that duplicates the standard status message corresponding to the provided status code into the body:
app.get('/a', (req, res) => {
res.sendStatus(500)
})
HTTP/1.1 500 Internal Server Error <--- this status message (aka "reason phrase")
<response headers>
Internal Server Error <--- gets duplicated here in body
See here for its implementation. There is no obvious need to do that, because the status message (the text after "500 ") will be there regardless. The above is NOT a normal HTTP idiom. Who knows why it was added into the express response. Moreover, when you send a non-empty body along with a status to a browser, it will render that body rather than a standard stylish page:
res.status(500).send() is sufficient to respond in a standard way:
app.get('/b', (req, res) => {
res.status(500).send()
})
HTTP/1.1 500 Internal Server Error <--- status message
<response headers>
<--- empty body
This is what everyone expects if there is nothing to say beyond status code & message.

no it's not for special routers like delete
The diffrence is res.status() only sets header and when you send response (res.send()) it will send to user
but res.sendStatus() sends the response at the moment without response body

Related

Express server Error 400 is not returning json message

I am submitting a form and if the form id already exists in the database, I am returning status 400 with a message saying that the form exists.
res.status(400).send({
status: 400,
message: "Form exists"
})
When I read the response sent back from my express server, I am getting Bad request message instead of the custom message object that I am returning. If I replace res.status(400) with res.status(200), I am getting the expected custom message object.
Weird enough, I can get the custom message object when making the server call in development environment. I get Bad Request message from my production server and I don't know why the response is different when the environment is different. I am hosting this server on IIS Manager v10
So my question is should I use status code of 200 instead of 400 in this scenario? Is there a way to return a custom message from status 400? Based on my understanding, I should use 4xx status code if there is a client input errors eg there is already an existing ID or invalid inputs.
Edit: This is my code from my React app.
axiosInstance
.post("/form/some-endpoint", formData)
.then(function () {
navigate(ROUTE_SUCCESS_PAGE);
})
.catch(function (error) {
// eslint-disable-next-line no-console
console.log(error);
alert(error.response !== undefined ? error.response.data.message : error.message);
});
This is the actual screenshot of the response from prod server (I console log it)
But in development environment, I am getting the response that I wanted.
Postman response from Prod server:
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
Adding the <httpErrors existingResponse="PassThrough" /> to the server's web.config file on IIS Manager resolved my issue. Based on my understanding, bypassing the http error handler and not letting IIS to send its response is the solution that I need.
should I use status code of 200 instead of 400 in this scenario
TLDR: It depends on the usage.
If your intent is to Update a form, like using a PUT request, you should require an id and if that id does not exist, return 404.
If you are looking to Create a new form, like using a POST request, with an id or other meta data and one already exists matching the id or meta data (e.g. groupId), then 400 is fine but it could be better to use 409 stating that there is a conflict with the existing state, that being a preexisting form id or meta data. Though you don't often pass an id to a POST create request.
The full list of codes is a great place to start, but sometimes it helps to see how certain codes are used in production APIs. A good place to look is the GitHub API which shows the possible status codes for each endpoint along with a description. Take the Pulls API for example, just searching for 40 on the page gives you a lot of insight about when certain codes are used.
Comparing these statuses with your example, if you look at the PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge route, they use 409 whenever the state is not matching as they describe...
Conflict if sha was provided and pull request head did not match
This seems similar in nature to the POST request described above.
At the end of the day the crucial part is to get in the correct grouping (i.e 2xx, 4xx, etc.) after that it's more about being consistent across your API than matching the codes to exact best option. Also everyone is different and some may choose different codes for the same use case.
As far as changing the response itself on 400 status, you should be able to achieve this by setting statusMessage directly and then call res.end.
function(req, res) {
res.statusMessage = "Form exists";
res.status(400).end();
}
Also see https://stackoverflow.com/a/36507614/6943587

How to set cache headers only if there isn't an error in sending the response in Node.js

I am doing this essentially:
app.get('/:id.:ext', (req, res) => {
const remote = bucket.file(`images/${req.params.id}.${req.params.ext}`)
// if (isProd)
// res.set('Cache-Control', 'public, max-age=604800')
remote.createReadStream({ validation: false })
.on('error', error => {
console.log(error)
res.send(`data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7`)
})
.pipe(res)
.on('end', () => {
res.set('Cache-Control', 'public, max-age=86400')
})
})
When there is an error, I just return an empty image. But in this case, I don't want to set the cache headers because I don't want the blank image to be cached.
So I try setting the cache headers after the response is sent, but they don't go through.
If I set the cache headers before piping the response, I cache the error in case of error.
Wondering how to get around this.
You can't do what you're trying to do the way you're trying to do it. The sequence of an http response is to send the http headers, then start sending the respond body. So if you're piping a response body (like you are), you HAVE to send the headers first. You can't start sending the response body, then changing your mind about the headers. They've already been sent.
And, you can't send headers after the http library has already starting sending the respond body. Starting to send the response body writes out the currently stored state of the http headers that go with this response and then starts writing the response.
As best I know, the only way to deal with an error that occurs in the middle of sending the http response body is to close the http connection prematurely. The client will see the socket close without seeing the end of the http response and will understand that it got a terminated, unfinished response. You don't get a chance to send another response at that point. Error handling for that case will need to be client-side in order to decide what to do.
Another option is to prefetch all the data you want to send to the client BEFORE you send anything. This allows you the most chances to determine if anything is going to cause an error before you've started sending the http response and then you can craft the entire response to match your error condition. You obviously can't use something like .pipe(res) if you're going to do that. Instead, you've have to load the entire response into memory (or at least a chunk of the response if you're going to send it in chunks) and only when that has been successfully pre-flighted and loaded and ready to go do you start sending the response.
Also, another way to avoid getting an error image cached is to do a 301 (temporary redirect) to the error image URL rather than return it as the response to the original request. Then, when the browser loads that redirected URL and gets the image, it will not cache it as the original URL.

How to add express middleware at the end of the chain that gets invoked no matter what (OK/FAIL responses)?

Is there a way to add middleware to the end of an express app or router chain that gets called to track whether or not the res / response was sent or not?
I mean, regardless of if:
A response is sent (string, JSON, etc.)
A static served file.
No file found in the static folder.
A catch-all callback was reached.
An error middleware was reached.
Example
For instance, if I wanted to log everything...
whether a response was successful or not, ie: it served a file via a express.static( ... ) middleware, some data fetched from a DB, or a custom middleware, or again... if it failed / threw an error...,
is there a way to invoke a callback at the very end?
So far from what I can understand, it seems like, by design, if a static file gets served successfully (via express.static), it doesn't call next(), so the chain stops there.
And for any custom-made middlewares using res.send(), you normally wouldn't want to call next() afterwards since it could cause some undesirable side-effects (errors with headers getting resent).
For error-handlers, that's easier since all unsuccessful responses can be caught here.
But how can it output both successful / unsuccessful responses? Could this be something that should be done without middlewares?
The solution I went with ended up being slightly different from this one by #idbehold, but in a nutshell, at the very top of the express app middleware chain, I had to hook a callback to the res Response object's finish event which gets triggered for most (all?) HTTP status-codes I needed to track a successfully served request.
app.use( ( req, res, next ) => {
res.on( 'finish', () => {
var codeStr = String( res.statusCode );
codeStr = codeStr[res.statusCode < 400 ? 'green' : 'red'];
var output = [req.method.green, req.fullUrl().green, codeStr];
trace( output.join( ' ' ) );
} );
next();
});
I can now get things like:
EDIT
Alright! So provided you also have an error-handler at the "end" of your middleware chain that serves something with an error 404 code, that will trigger the finish event on the res object.
Example of such an error-handler:
app.use( ( err, req, res, next ) => {
trace( "Error!".red );
trace( err );
res.status( 404 ).send(); // Triggers 'finish' on res.
})
There's a conceptual difficulty with the asynchronous architecture of node.js and Express for doing this. I'll describe the general problem and then discuss a few possible work-arounds.
First, each Express handler can be asynchronous. Thus, it gets called and returns pretty much immediately and nobody outside of that world knows whether it is still waiting for some asynchronous operation to finish before eventually sending its response or if it just failed to do anything. You literally can't tell from the outside world.
Second, you can monitor a given request to see if it either calls an error handler or if it sends a response. There is no way to monitor a request handler to see if it just failed to send anything because of the reason above - you have no way of knowing if its still waiting for some asynchronous thing to finish.
So, here's the best I could recommend:
Hook res.end() to see when it gets called. This is an indication that the response is now done (whether error or success). You can see an example of doing that in the express-afterware module that Medet linked in an above comment. The general idea is that you'd have your own middleware somewhere very early in the chain that overrides res.end() so you can see when its called. That early middleware would just install the override and call next() to continue the handler chain. Then, when the response is finished, your override would see that res.end() got called. This should work for all cases where the response is sent.
Then, you still need to handle cases where no response is sent (which is probably due to faulty code since all requests should get a response eventually). The only way I know of to do that is to implement some sort of timeout for a request. You can either use a built-in mechanism server.setTimeout() or you can implement your own inside your middleware (same middleware as describe in step 1). Then, after some timeout that you specify, if no response has yet been sent, you would take over and send some error response.
Install your own error middlewares early in the chain that will see and log all errors. Note that res.end() will still be called so the behavior in step 1 will still be triggered even for errors (error responses still call res.end()).
You can trigger a piece of code at the end of a request by using the finish event of the response object. The finish event is emitted when the response has been sent to the client and all the data has been flushed to the network.
app.use(function(req, res, next) {
res.on('finish', function() {
console.log('Request finished');
});
next();
});

Proper Node.js API for determining whether or not `100 Continue` was sent

I have a strange edge case of HTTP and HTTP-like handling where I have to support some broken clients. Specifically, a client will make an HTTP PUT request, and I need to send a 200 OK after the request headers are received, before the client sends its request body. Normally, I do this:
app.put('/*', function (req, res, next) {
res.socket.write('HTTP/1.0 200 OK\r\n\r\n');
/* Pipe socket and handle data here */
}
However, with newer versions of Node.js (v6.2.2 as of this writing), when a client connects with a proper HTTP/1.1 request and Expect: 100-continue in its request headers, the HTTP server will (correctly) send an HTTP/1.1 100 Continue message, immediately before I get a chance to send my own response status line. As a result, the client would get two status lines:
HTTP/1.1 100 Continue
HTTP/1.0 200 OK
This isn't a huge problem. I just need to detect when the Node.js HTTP server took care of the status line, so I don't send a duplicate. The trick is, I don't think this API is properly exposed. I prodded around and came up with this method:
app.put('/*', function (req, res, next) {
if (!res._sent100) {
res.socket.write('HTTP/1.0 200 OK\r\n\r\n');
}
/* Pipe socket and handle data here */
}
My Question: Is there a better way to detect when the built-in HTTP server has sent 100 Continue than by using res._sent100?
There is an HTTP server checkContinue event. However, if I handle that event then the normal events don't fire. I'm using this in conjunction with Express, and I need the normal request events so that the normal middleware stack will run. If I could handle checkContinue, write my own property to res, and then pass it back to the normal stack for handling, then all would be well. But, I don't see a documented way to do this.
This seems to work:
server.on('checkContinue', (req, res) => {
res.mySent100 = true;
res.writeContinue();
server.emit('request', req, res);
});
(where server is the HTTPServer instance that is serving your Express app)

Express Request Post-Processing

I haven't been able to find anything in express's documentation, but is there such thing as request post processing? I am using a custom token authentication scheme using passport and I would like the ability to automatically update the token in a response header after making a request, mostly a hashed timestamp for authentication purposes. For discussion purposes, let's say I want the following function to execute after each request:
function requestPostProcess(req, res){
if (res.status == 200)
{
res.token = updateToken();
}
}
Ideally, I'd like to be able to do this without having to call next() in each of my routes. Is that even possible?
If you want to add the token to the response,
1) You can create a middleware that adds the token as soon as the request comes, and before it is processed. Put this before request handlers.
Example,
app.use(function(req, res, next){
res.token = updateToken();
next();
})
The glitch here is that, the token will come with all the responses but that can be something you may accept, since it is a timestamp. Plus you can even handle errors using middlewares, and remove the token when the status is not 200.
Advantage: minimal changes required, with proper error handling it works great.
Disadvantage: it tells the time when request was received and not when the response was ready.
2) If you want to put the response after the process is completed, meaning the time when the response was ready, then you may need to create a utility function that sends back all the responses, and you always call that function. That utility function will check the status and appends the token.
function sendResponseGateway(req, res){
if (res.status == 200)
{
res.token = updateToken();
}
res.send()
}
Now whenever you are ready to send response, you can call this function.
Disadvantage: function needs to be called everywhere and you will not be writing "res.send" anywhere.
Advantage :you have a gateway of sending response, you can do additional stuff like encoding, adding more headers etc. in that function and all those response modification stuff happens at one place.

Resources