Node & Express Endpoint always returns 200 - node.js

I am having issues with a block of code in my node.js API. I have a simple JWT authentication API that is working as expected in terms of logging in and authentication. Howvever I cannot get express to return a response status other then 200.
If I enter an invalid username or password for the login end point, the response I receive is an empty 200 response, despite the fact the below code executes the catch block, and I return a response of 500 with my error. from the post method. This is getting lost somewhere, and converted to the empty 200 response. On succesfull login the return res.status(200).json.... code returns the correct response.
I have the same issue on all endpoints, all error responses are return as an empty 200 response.
Could any one advise.
app.post('/user/login', async (req, res) => {
const email = req.body.user.email;
const password = req.body.user.password;
try {
const authServiceInstance = new AuthService();
const { user, token } = await authServiceInstance.Login(email, password);
return res.status(200).json({ user, token }).end();
} catch(e) {
console.log('Error in login: ', e);
return res.json(e).status(500).end();
}
})

Related

Instagram 401 unauthorized

Im using the graphql api endpoint to call the endpoint to retrieve a posts information using the function below.
async function getInstagramData(url: string) {
const postHash = '';
const postAPI = `https://www.instagram.com/graphql/query/?query_hash=${postHash}&variables=${encodeURIComponent(
`{"shortcode":"${getShortcode(url)}"}`
)}`;
console.log(postAPI);
try {
const respone = await axios.get(postAPI);
const json = await respone.data;
if (!json.data) return null;
return json.data['shortcode_media'];
} catch (error) {
console.log(error);
return null;
}
}
This works fine locally but doesn't work on the server as I get a 401 unauthorized. After looking into the response I found
data: {
message: 'Please wait a few minutes before you try again.',
require_login: true,
status: 'fail'
}
My question would be how I should log into the API.
From my understanding, I have two solutions (not sure if any of them are possible)
Call the Login API Endpoint store the cookies that are returned and use them when calling the endpoint above.
Is it possible to use a facebook APP ID in my get request to call the request via my application.

postman (thunder client) can send request but axios cannot

I am trying to send http requests using axios to my node backend. For some reason, axios keeps returning a 500 (Internal Server Error) even when thunder client (dollar store version of postman) is able to send the request and get a proper response.
index.js (server)
app.get('/api/login', async (req, res) => {
try {
const user = await User.findOne({ email: req.body.email })
if(user===undefined) { res.status(404).json("user not found"); }
const validPassword = await bcrypt.compare(req.body.password, user.password)
!validPassword && res.status(400).json("wrong password")
res.status(200).json(user)
} catch (err) {
res.status(500).json(err)
}
})
Login.js (frontend)
const login = (email, password) => {
console.log(email + ': ' + password)
axios.get('http://localhost:8800/api/login', { email: email, password: password })
.then((response) => console.log(response))
.catch((err) => console.log(err.response))
}
err.response returns no useful data and err.response.data is a blank object. I've tried to edit the request header, but it is already 'application/json'. Again, this request works on thunder client and I made sure that the data I passed in was correct through the console.log(email + ': ' + password . I've been trying to fix this issue for hours so please help. Thank you in advance.
Update: I had previously binded the login function to an onClick to a button, but I put the axios function directly into the brackets instead of login(email, password). The issue persists.
Second Update: I followed the comments' advice and console logged the error on the terminal. It returned TypeError: Cannot read properties of null (reading 'password'). This was strange because in the function, I had console logged password and it returned the proper text. It also says that it cannot find a user within my database that uses the email I am currently using, but even when I pass in the exact email I use in thunder client requests, I still get the error. I think the data is not getting there properly.
Third Update: My hypothesis is confirmed. In index.js, I made the route console log req.body.email and it returned undefined. I passed in an object that I JSON stringified and when console logged in the browser, it returns a proper object. The request is sending an object with undefined properties although I am passing in an object with values
In this case, the issue was that the request was a get request, not a post request. Get requests do not take in data while post requests do. Here is the fix:
index.js (server)
app.post('/api/login', async (req, res) => {
try {
const user = await User.findOne({ email: req.body.email })
if(user===undefined) { res.status(404).json("user not found"); }
const validPassword = await bcrypt.compare(req.body.password, user.password)
!validPassword && res.status(400).json("wrong password")
res.status(200).json(user)
} catch (err) {
res.status(500).json(err)
}
})
If you have to receive the request parameters in body (mainly in json format) then you have to go with POST type request.
In the GET type request, you can get request parameters in the form of params and query string.
Parameters may be either part of path:
myapi/customers/123
or a query string:
myapi?customer=123
More details can be found here:
https://www.restapitutorial.com/lessons/httpmethods.html

How to fix the "cannot set headers after they are sent to the client" error in node?

I know this question has been asked several times, but the solution provided didn't work for me.
I have a protected route to find a user. The request is validated by an authenticate middleware, which basically checks if the user's cookie is valid, and then the route getUser is called. The route works well when I don't use the middleware, so the issue may come from authenticate.
I have used return res.status(200).json({}) as suggested.
When testing the route with the cookie, chai makes two calls. The first one succeeds, but as soon as the route is hit, another call is made, without any cookie. Weird. In Postman, same thing. It works wonderfully without authenticate, but returns unauthorized with it. In the terminal, the error is:
[ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Here is the authenticate middleware and the route:
// router
const router = express.Router();
router.get("/user/:id", authenticate, getUser);
// authenticate
const authenticate = (req: Authenticate, res: Response, next: NextFunction) => {
const { mycookie } = req.cookies;
if (mycookie) {
jwt.verify(mycookie, process.env.JWT_TOKEN_KEY, (error, parsedToken) => {
if (error) {
return res.sendStatus(403);
}
req.cookie = { _id: parsedToken._id, locale: parsedToken.locale };
return next();
});
}
return res.sendStatus(401);
};
export default authenticate;
// the get - user/:id route
const getUser = async (
req: GetUser,
res: IResponse
): Promise<IResponse> => {
try {
const user = await UserControler.findUserById(req.params.id);
return res.status(200).json({ user });
} catch (err) {
throw new Error("error.unknown");
}
};
export default getUser;
How to fix this?
In your authenticate functions, you forgot to add an else statement to if (mycookie).
Unauthorized will therefore always be sent, which is clearly the reason why you get unauthorized with a good cookie, and then as unauthorized as already been sent, the error you describe will be throw when getUser tries to sent the http response.
Wrap return res.sendStatus(401); in an else statement and it should work fine.

NODE/EXPRESS: [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I'm working on building an node/express backend and continue to receive the following error: (node:35061) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client. I'm not exactly sure what i am doing wrong here... Can someone educate me on what the issue might be? TIA!
Route
userRoutes.post('', async (req, res) => {
try {
const { email, password } = req.body;
const validate = await signUp.validate({ email, password });
res.send(validate);
const newUser = new User({ email, password });
const sessionUser = sessionizeUser(newUser);
await newUser.save();
req.session.user = sessionUser;
res.send(sessionUser);
return;
} catch (error) {
res.status(400).send(parseError(error));
}
});
The problem lies here in try block
try {
const { email, password } = req.body;
const validate = await signUp.validate({ email, password });
res.send(validate); //over here
const newUser = new User({ email, password });
const sessionUser = sessionizeUser(newUser);
await newUser.save();
req.session.user = sessionUser;
res.send(sessionUser); //over here
return;
}
this means is that for a given client request the server previously sent a response (either a success response with the resource requested or error response for a bad request) back to the client and now is unexpectedly trying to send another response
Solution
The simple fix for this error is to add javascript return statement to the response being sent from the if conditional to ensure that the request handler function exits(terminate) excuting code with the function once a response has being sent to the client.
The description for the return statement on MDN states
When a return statement is used in a function body, the execution of the function is stopped. If specified, a given value is returned to the function caller.

API Token returning 401 Unauthorised when its working in URL

I am making a Multi-Purpose API Service and as I got the token in the URL working perfect and authorising as expected with a 200. I've been having issues with the token not authorising with curl command or superagent, as its always return a 401 error.
auth.js
const { DB } = require('../src/Routes/index.js');
module.exports = function auth(req, res, next) {
if(!req.query.apiKey) {
return res.status(401).json({"error": "401 Unauthorized", message: "API Token is missing in the query. You will need to generate a Token and put in the apiKey query."})
} else {
let check = DB.filter(k => k).map(i => i.apiToken);
console.log(check);
let t = check.some(e => e == req.query.apiKey)
if(t !== true)
return res.status(401).json({"error": "401 Unauthorized", message: "The API Key you provided is invalid. Please refer to our Docs () and Generate a Token ()"});
return next();
}
}
This is the middleware for the token, I am using this in my routers so then the token will authenticate. However, if I remove the if statement for checking if an API Token is present. It seem to fix the issue kinda but always authenticates with any key (even ones not saved in the db) and is still not properly fixed.
and an example for requesting endpoint with token on a Discord Command:
const { MessageEmbed } = require("discord.js");
const { get } = require("superagent");
exports.run = async (bot, message, args) => {
const { body } = await get(`https://example.com/generators/3000years`)
.query({ image: message.author.displayAvatarURL({ dynamic: true, size: 2048 }) })
.set("Authorization", `Bearer MY_TOKEN`);
const embed = new MessageEmbed()
.setTitle(`**3000 Years**`)
.attachFiles({ attachment: body, name: "3000years.png" })
.setImage("attachment://3000years.png")
.setColor(`#ed8a5c`);
message.channel.send(embed);
}
You can see that if I authorise with Superagent, it will not work and return a 401 Unauthorised in the console.
I would like to ask why this is doing this and if I did something wrong. Any help is appreciated.

Resources