Why Send API Status Codes? - node.js

I'm building my first API with node.js and was wondering do I need to ensure that a status code is send with every response or is it ok to simply use a boolean.
Is it critical for security or something?
So code wise:
return res.status(403).send({ message: 'No token provided.' });
Versus
return res.json({ success: false, message: 'No token provided.' });
Thanks.

HTTP status codes are understood by every HTTP client, be it cURL, a browser, a web proxy or a library for a programming language.
If you use just 200 OK status code, then a client that doesn't know your application won't be able to tell success from error. In case of proxies this may even cause caching problems.
On top of it, using codes properly makes it easier for the user to write a client. For instance I could use response.raise_for_status in Python Requests or $.get().then(onSuccess, onError) in jQuery.

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

What is a good approach for a /forgot route to respond?

So when you are responding (server-side) to a /forgot-password route what is the best response to it? ( In the situation that you don't want to expose what users you have in the DB and still hint the app that the user does not exist)
I was faced today with this scenario in which I respond in that route with 200 but my colleague that is working on his app wanted me to send an error so he could implement an SMS recovery form.
Imagine this:
POST /forget-password
Body: { username: 'test' }
And you respond with 404/400 and an error message like:
{
statusCode: 404,
message: 'User not found'
}
Is this a good practice? Or not?
Why I am asking this? When you are responding to a client with 404 you expose what usernames you have in your database and this might be a security breach.
What is the best approach for this, and why?
In my opinion, I'm guessing that you should respond with 200, in either case, to not let any kind of scenarios for the client.
You had it correct at the beginning. You should return an HTTP 200. This is to prevent someone from looping through with various usernames to figure out who exists, etc.
What I typically do is accept whatever they put in, then email the provided information either a "sorry, that account doesn't exist, create one here" or "here's your link to reset your password".

firebase Http function error

I have written a Firebase Http function.
When successful it returns status 200 with some data.
When it errors I want the client (which is using axios.post) to use a standard error handler which means showing the error.message property.
If I send an error code back with data - yes, I can access that data/message etc in error.response.data, but that isn't a pattern I can use for all errors - some errors might occur that don't give a response or data property.
So if I just want to access error.message at the client I need to be able to set that message but at the moment if I use for example:-
res.status(520).send('My custom error message')
I get:
Request failed with status 520
in the error.message, then I have to go to the error.response.data to get the actual message I want to display.
How could I do this so that I just use error.message regardless? I have tried using
res.status(x).send({error:customerror})
also tried
res.statusText = customerror
As you can see on Axios documentation, you have to use the error.response to get info from your custom message. You wouldn't be able to set the value on error.message on Axios.
If you really need to use error.message, you have to make a custom function to change it on cliente.

Accessing QCMobile API

I'm currently tasked with accessing data from the Department of Transportations QCMobile API, located here.
I've made an account and have obtained my key. I've tried accessing it through Ajax calls, Node's Request and https modules, and now I'm just trying to get a response via Curl.
Every time I try to access it I get the same error: error 403, Forbidden.
My URL appears to be properly formed, as seen here:
https://mobile.fmcsa.dot.gov/qc/services/carriers/44110/basics?webKey=xxxx
When I run it from Node or from an Ajax call, I only get 403, Forbidden.
Here is my relevant Node code:
this.url = 'https://mobile.fmcsa.dot.gov/qc/services/carriers/' + dotNumber + '/basics' + '?webKey=' + this.webkey;
this.options = {
method: 'GET',
uri: this.url,
};
this.getDoTData = function() {
request(this.options)
.then(function (response) {
// Request was successful, use the response object at will
console.log(response);
})
.catch(function (err) {
// Something bad happened, handle the error
console.log(err);
});
}
When I run it via Curl, I get the same 403 with some extra detail:
curl: (56) SSLRead() return error -9806
I was wondering if anyone has any ideas as to if I'm accessing this API incorrectly. There doesn't appear to be much documentation, and the page on their site where you can submit technical questions seems to be broken.
Thanks for any insight.
This web service seems to be down for the time being. These problems started during the maintenance window on weekend of Nov 18th, and it has been in varying degrees of non-operation since then.
This is the response I got from FMCSA customer support today:
I do apologize about the inconvenience however, we have been experiencing technical difficulties with the App for a few weeks now. Our IT department is currently working on it however, at this time I do not have an exact time on when it will be fixed.

Token already used error while fetching access token

I am trying to setup a node.js application to use the Elance API using OAuth2.0
I am using passport.js to connect to the elance api and so far am able to get the code properly.
Before using the api methods, I then need to obtain the request token using a post request.
However, I am getting a 'Code Already Used' error.
Here's my callback code
app.get('/callback',
passport.authenticate('elance', { failureRedirect: '/failure' }),
function(req, res) {
console.log('CODE : ' + req.query.code); // this is getting displayed properly
var payload = {
code: req.query.code,
grant_type:'authorization_code',
client_id: auth.CLIENT_ID,
client_secret: auth.CLIENT_SECRET
};
request.post('https://api.elance.com/api2/oauth/token/', payload)
.then(function(response) {
var x = response.getBody();
console.log('resp::::'+x);
res.redirect('/success');
});
});
I am using requestify to perform the post request and am not using/calling to the server with the temporary code.
Here's the generated error:
... [Sat, 29 Mar 2014 05:54:15 GMT] "GET /callback?code=F9t-zztOLJ3IOlbGXlsqous686HstXqkv7etrvEnF11Vg4M HTTP/1.1" - - "-" "Mozilla/5.0 (X11; Linux i686 on x86_64; rv:30.0) Gecko/20100101 Firefox/30.0"
InternalOAuthError: Failed to obtain access token (status: 401 data: {"errors":[{"code":null,"description":"Code already used."}]})
Perhaps the proper way of implementing this with Elance is to write a strategy. Just use one of the other ones published like Facebook as a model, or a simpler one like GitHub. It should be fairly straightforward, and better encapsulated. Here's a complete list: http://passportjs.org/ if you want to explore. Better yet, making this module reusable, others can then benefit from it in a more standard way.
Strategies will exchange the code for the token for you. Likely the reason the code is used and you get that error. That is part of the the standard OAuth2 flow.
I had the same problem, and had to work with Elance support to get it figured out. This error occured for me because multiple simultaneous requests were coming in for the same user from multiple threads/servers with the same API key.
In my case, it was a pool of server threads that were doing background work and we needed to synchronize the login so it only happened once. Multiple threads can re-use the same access_token, just not apply for a code and then an access_token/refresh_token in parallel.
This could also happen because you have multiple people / build servers running test cases which are asking for codes and then access_tokens in parallel.
Following are the points which seems to be vital in order to receive the token:
Setting the correct content-type and Content-Length values.
The request should be a HTTPS request.
Method should be POST.
I also installed and used Open SSL, just to avoid any issue caused due to non secure calls made by the server.
Calls made using Requestify were failing each time, even when I set the identical header information mentioned in #1 above. As visible in the attached screenshot, it works fine with normal https request calls.
JSON response from subsequent queries was obtained from the following code:
var request = require("request");
var jobURL = 'https://api.elance.com/api2/jobs/my?access_token=' + _token;
request(jobURL, function (error, response, body) {
res.write(body);
res.end();
});

Resources