Axios POST request sending but not being recieved - node.js

I know this has been asked before but any solutions I've tried have failed to get results so far. I'm new to Axios and I'm trying to test sending a POST request, and it seems like the request is indeed sent, but it never ends up actually being received, despite showing a 200 OK status code. I've been troubleshooting a while, but no amount of changing headers or fiddling with the server seems to have changed anything.
Sending Request
handleSubmit(event){
event.preventDefault();
var myObj = {
email: this.state.userEmail,
password: this.state.userPassword,
failedLogin: this.state.failedLogin
}
// validate login
axios.post("/login", myObj)
.then(function(response){
console.log(response.data.test);
})
.catch(function (error) {
console.log(error);
});
}
Receiving Request
The alert with "receive" is never executed.
userRoutes.route("/login").post((req, res) => {
console.log("sent");
res.send({test: "test"})
});
And my requests/responses and console:
request
response
console

Axios signature for post is axios.post(url[, data[, config]]). So your object should be written as 3rd parameter. Also, your post url must be complete. Otherwise you will get invalid url error.
Sending Request
axios
.post("http://localhost:3000/login", null, yourObj)
.then((res) => {
console.log(res.data.test);
// Result: test
})
.catch((err) => console.log(err));
Receiving Request
app.post("/login", (req, res) => {
res.status(200).json({ test: "test" });
});

Sure enough, as #Phil and #trognanders suggested, the problem was because my Express middleware was configured incorrectly, hence not an Axios problem.

Related

request body is undefined when trying to POST in express

For some reason, request body is undefined when trying to make a post request:
here is my router:
router.route("/").post(schoolController.createSchool);
here is what I put in schoolController for createSchool:
exports.createSchool = async (req, res) => {
try {
console.log(req.body);
// return undefined
const newSchool = await School.create(req.body);
res.status(201).json({
status: "success",
data: {
school: newSchool,
},
});
} catch (err) {
res.status(400).json({
status: "fail",
message: err,
});
}
};
adding on, I am following jonas's nodejs course on udemy, and he has almost the exact thing as this, except its for handling tour requests instead of school
The problem you are facing here is likely that you have not configured the body-parser middleware correctly. The normal req will not contain any property by the name body. Only once the request passes through the body-parser middleware, the body key will be added to the req. You can try console logging req. If the request is logged correctly, it is more than likely that you need to look into configuring you bodyparser middleware correctly before you can use req.body in your code.

Cannot GET from Express.js PUT route, why?

Is there any reason you cannot execute a GET request from inside an Express.js router.put()?
I have two routes. The exact same api call works in a router.get() route and hangs in the router.put().
I've confirmed that
This works:
router.get('/:id', async (req, res) => {
const { headers } = req;
let result;
try {
result = await axios({ method:'get', url: '/some-url', headers });
} catch(error) {
res.status(500).send(new Error('myError');
}
res.send({ result });
});
This does NOT work:
router.put('/:id', async (req, res) => {
const { headers } = req;
let result;
let finalResult;
try {
result = await axios({ method:'get', url: '/some-url', headers });
} catch(error) {
res.status(500).send(new Error('myError');
}
// logic based on the result of the above GET determines what the value of `finalResult`
finalResult = { some: 'data' };
res.send({ finalResult });
});
Even though axios({ method:'get', url: '/some-url' }) is the exact same in both routes, it works in one and not the other.
The router.put() route always hangs for a long time and eventually Node outputs:
Error: socket hang up, code: 'ECONNRESET', etc...
Appreciate any help, I've spent over a day scratching my head over this.
No there's no such thing in express. Try hitting the GET request from postman or curl and see if response is coming. The root cause could be an invalid get request you're trying to make or that server on which you are making GET request could be down. You can run following to validate
app.put('/',async (req, res) => {
let response = await axios.get('https://google.co.in');
console.log(response.data);
res.send({"works": "hello"});
});
Root cause of my problem:
The http Headers had a key of Content-Length that prevented GET calls to resolve correctly.
Since these api calls occurred within a router.put() callback, the Headers had a Content-Length pointing to the size of the payload "body" that was being PUT to begin with.
Solution:
Remove that Content-Length field from my Headers when doing GETs inside router.put(), such that the GET has all the other Headers data except for Content-Length
Unfortunately, NodeJS just threw that Error: socket hang up message that was not very descriptive of the underlying problem.

Client (react) cannot access response from Server (express)

I'm working on a post route for an express.js server. I've got a validation function that if not passed, returns a 400 code with message. The client (React), receives the 400 code, but I cannot access the message sent by the server.
This is within the POST in express:
const { error } = validate(req.body);
if (error)
return res
.status(400)
.send(error.details[0].message);
This is the submit routine in React:
doSubmit = async () => {
const { username, password } = this.state.data;
const result = await login({ mail: username, password });
console.log('result', result);
};
Login is only a wrapper for axios.post method:
export async function login(user) {
try {
return await http.post(apiEndpoint, user);
} catch (ex) {
console.log(ex.message);
return ex;
}
}
Currently, the code works as it is. Submitting an invalid input, such as a password below 5 characters, i get the following in the client:
POST http://localhost:3000/api/auth 400 (Bad Request)
Request failed with status code 400
result Error: Request failed with status code 400
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:78)
at XMLHttpRequest.wrapped (raven.js:363)
However, if I change the status code sent by the server to "200", I get:
result {
full response here along with data property..
data: ""password" length must be at least 5 characters long"
}
I've been reading the Express documentation. It doesn't say anything about not sending the response if the code is 400 (although it makes sense to send nothing if bad request). I've also toyed a bit with 'body-parser' but didn't get different results.
However, if I test in postman, it works like a charm! With same input, i get the status code and the message.
Finally, it's ok to validate both the input sent (client) and the data received(server) right? If so, let's say the client is OK with the input, but the server is not. Should the server respond with whatever the problem is (what i'm trying to achieve), or simply say 'ERROR' (current scenario)?
Thank you.
Axios code example, may be given code fix your issue. The issue is with your parameters.
axios({
url: '/login',
method: 'post',
params: { username: 'cedas', password: 'fredsed' }
}).then(response => {
resolve(response)
})
.catch(error => {
reject(error)
});
})
Well, in the end, the problem was accessing ex.message, instead of ex.response ... Cheers.

Making external get request with Express

so I have the following Scenario; I have a private API key that Angular will show in XHR request. To combat this, I decided to use Express as a proxy and make server side requests. However, I cannot seem to find documentation on how to make my own get requests.
Architecture:
Angular makes request to /api/external-api --> Express handles the route and makes request to externalURL with params in req.body.params and attaches API key from config.apiKey. The following is pseudocode to imitate what I'm trying to accomplish:
router.get('/external-api', (req, res) => {
externalRestGetRequest(externalURL, req.body.params, config.apiKey)
res.send({ /* get response here */})
}
You are half way there! You need something to make that request for you. Such as the npm library request.
In your route something like
var request = require('request');
router.get('/external-api', function(req, res){
request('http://www.google.com', function (error, response, body) {
console.log('error:', error); // Print the error if one occurred and handle it
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
res.send(body)
});
})
This allows you to make any type of request using whatever URL or API keys you need. However it's important to note you also need to handle any errors or bad response codes.
The accepted answer is good, but in case anyone comes across this question later, let's keep in mind that as of February, 2020, request is now deprecated.
So what can we do? We can use another library. I would suggest Axios.
Install it and do something like:
const axios = require('axios')
const url = "https://example.com"
const getData = async (url) => {
try {
const response = await axios.get(url)
const data = response.data
console.log(data)
} catch (error) {
console.log(error)
}
}
getData(url)

Proper way to set response status and JSON content in a REST API made with nodejs and express

I am playing around with Nodejs and express by building a small rest API. My question is, what is the good practice/best way to set the code status, as well as the response data?
Let me explain with a little bit of code (I will not put the node and express code necessary to start the server, just the router methods that are concerned):
router.get('/users/:id', function(req, res, next) {
var user = users.getUserById(req.params.id);
res.json(user);
});
exports.getUserById = function(id) {
for (var i = 0; i < users.length; i++) {
if (users[i].id == id) return users[i];
}
};
The code below works perfectly, and when sending a request with Postman, I get the following result:
As you can see, the status shows 200, which is OK. But is this the best way to do this? Is there a case where I should have to set the status myself, as well as the returned JSON? Or is that always handled by express?
For example, I just made a quick test and slightly modified the get method above:
router.get('/users/:id', function(req, res, next) {
var user = users.getUserById(req.params.id);
if (user == null || user == 'undefined') {
res.status(404);
}
res.json(user);
});
As you can see, if the user is not found in the array, I will just set a status of 404.
Resources/advices to learn more about this topic are more than welcome.
Express API reference covers this case.
See status and send.
In short, you just have to call the status method before calling json or send:
res.status(500).send({ error: "boo:(" });
You could do it this way:
res.status(400).json(json_response);
This will set the HTTP status code to 400, it works even in express 4.
status of 200 will be the default when using res.send, res.json, etc.
You can set the status like res.status(500).json({ error: 'something is wrong' });
Often I'll do something like...
router.get('/something', function(req, res, next) {
// Some stuff here
if(err) {
res.status(500);
return next(err);
}
// More stuff here
});
Then have my error middleware send the response, and do anything else I need to do when there is an error.
Additionally: res.sendStatus(status) has been added as of version 4.9.0
http://expressjs.com/4x/api.html#res.sendStatus
A list of HTTP Status Codes
The good-practice regarding status response is to, predictably, send the proper HTTP status code depending on the error (4xx for client errors, 5xx for server errors), regarding the actual JSON response there's no "bible" but a good idea could be to send (again) the status and data as 2 different properties of the root object in a successful response (this way you are giving the client the chance to capture the status from the HTTP headers and the payload itself) and a 3rd property explaining the error in a human-understandable way in the case of an error.
Stripe's API behaves similarly in the real world.
i.e.
OK
200, {status: 200, data: [...]}
Error
400, {status: 400, data: null, message: "You must send foo and bar to baz..."}
I am using this in my Express.js application:
app.get('/', function (req, res) {
res.status(200).json({
message: 'Welcome to the project-name api'
});
});
The standard way to get full HttpResponse that includes following properties
body //contains your data
headers
ok
status
statusText
type
url
On backend, do this
router.post('/signup', (req, res, next) => {
// res object have its own statusMessage property so utilize this
res.statusText = 'Your have signed-up succesfully'
return res.status(200).send('You are doing a great job')
})
On Frontend e.g. in Angular, just do:
let url = `http://example.com/signup`
this.http.post(url, { profile: data }, {
observe: 'response' // remember to add this, you'll get pure HttpResponse
}).subscribe(response => {
console.log(response)
})
res.status(500).jsonp(dataRes);
try {
var data = {foo: "bar"};
res.json(JSON.stringify(data));
}
catch (e) {
res.status(500).json(JSON.stringify(e));
}
The best way of sending an error response would be return res.status(400).send({ message: 'An error has occurred' }).
Then, in your frontend you can catch it using something like this:
url: your_url,
method: 'POST',
headers: headers,
data: JSON.stringify(body),
})
.then((res) => {
console.log('success', res);
})
.catch((err) => {
err.response && err.response.data && this.setState({ apiResponse: err.response.data })
})
Just logging err won't work, as your sent message object resides in err.response.data.
Hope that helps!
You could do this
return res.status(201).json({
statusCode: req.statusCode,
method: req.method,
message: 'Question has been added'
});
FOR IIS
If you are using iisnode to run nodejs through IIS, keep in mind that IIS by default replaces any error message you send.
This means that if you send res.status(401).json({message: "Incorrect authorization token"}) You would get back You do not have permission to view this directory or page.
This behavior can be turned off by using adding the following code to your web.config file under <system.webServer> (source):
<httpErrors existingResponse="PassThrough" />
res.sendStatus(status) has been added as of version 4.9.0
you can use one of these res.sendStatus() || res.status() methods
below is difference in between res.sendStatus() || res.status()
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')
I hope someone finds this helpful
thanks
I don't see anyone mentioned the fact that the order of method calls on res object is important.
I'm new to nodejs and didn't realize at first that res.json() does more than just setting the body of the response. It actually tries to infer the response status as well. So, if done like so:
res.json({"message": "Bad parameters"})
res.status(400)
The second line would be of no use, because based on the correctly built json express/nodejs will already infer the success status(200).

Resources