I am trying to update a collection in mongoDB after the user finishes some tasks. However, whenever I attempt to save the information and update mongo, I'm getting the error POST http://localhost:3000/updateSurvey/634124db6f 400 (Bad Request). Any ideas why my code isn't functioning correctly?
Backend js script
app.post('/updateSurvey', async (req, res) => {
try {
await client.connect();
var db = client.db('Admin_Db');
var collection = db.collection('Survey');
await collection.findOneAndUpdate({"_id": ObjectId(req.body.id)}, {completion: req.body.completion});
res.send("updated");
} catch (error) {
console.log(error);
res.status(400).send(error);
}
});
Main.js (this is how I am fetching the data from mongo)
fetch("http://localhost:3000/updateSurvey", {
method:'POST',
headers:{'Content-Type': 'application/json'},
body: JSON.stringify({id: surveyID, completion: true})})
.then(response=>{response.text()})
.catch(function(err){console.log("Fetch Problem: " + err)});
You don't have a route http://localhost:3000/updateSurvey/634124db6f exposed on your server. Therefore the 404 error. Since you are using a post call, just pass the surveyID in your body when making the post call using fetchAPI instead of sending it as a query param.
And make sure http://localhost:3000/updateSurvey is the route to which your are sending your data, without the surveyId in the URL.
Edit
Edits made as per request received in comments.
collection.findOneAndUpdate({"_id": id)}, {completion: req.body.completion});
should be:
collection.findOneAndUpdate({"_id": new ObjectId(id))}, {completion: req.body.completion});
_id is of type ObjectId in MongoDB. You are passing id as string. This should most likely be the error from what I can gather by the code shared in your question. You can cast a string to ObjectId by using the ObjectId class provided by the Mongo Driver for node. Even mongoose provides this class.
Related
Axios POST request sends data to Express sever but Error 404
Hello, world, I am trying to build a user authentication server for a project I am working on, but I am running into a problem trying to send a POST request to my Node.js Express server.
I want to send a POST request using Axios containing a username and password from the browser. But once sending the request it gives me a 404 Not Found error. The request has to go to http://website/api/login and my Node.js code should return either "authed" or "invalid". I tested the API inside Postman and that seems to be working. I also exported the request code from Postman and tested it with fetch API, xhr, and Axios, all returning the same result.
The server receives the data and handles it properly, but when I look in the Chromium debugger it appears that the request URL is just http://website/ and not http://website/api/login. I am honestly lost and I have tried what feels like everything, but I can't seem to make it work. Any help in pointing me in the right direction would be amazing! Thank you!
The code I use for the POST request is:
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;
const data = JSON.stringify({"username": username, "password":password});
const config = {
method: 'post',
url: 'http://website/api/login',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios(config).then(function (response) {
console.log(JSON.stringify(response.data));
}).catch(function (err) {
console.log(err);
})
}
This is what I see in the Chromium debugger:
Headers
This is my Node.js / Express code:
app.post('/api/login', function (req, res, next) {
scriptFile.authUser(req.body, function (err, state) {
if (err) console.log(err);
else {
if (state) {
res.send("authed");
} else {
res.send("invalid");
}
}
});
})
Thank you for any help I can get.
I am stupid,
Breakdown of what happened:
Everything was working fine except that I put the input data and submit button inside a form, which will refresh the page...
I fixed it by changing the form to a div.
Hey checking your chrome console pic looks like your post request is hitting the root api address 'http://website/' and not the full path 'http://website/api/login
I've got a small Express JS api that I'm building to handle and process multiple incoming requests from the browser and am having some trouble figuring out the best approach to handle them.
The use case is that there's a form, with potentially up-to 30 or so people submitting form data to the Express JS api at any given time, the API then POSTS this data of to some place using axios, and each one needs to return a response back to the browser of the person that submitted the data, my endpoint so far is:
app.post('/api/process', (req, res) => {
if (!req.body) {
res.status(400).send({ code: 400, success: false, message: "No data was submitted" })
return
}
const application = req.body.Application
axios.post('https://example.com/api/endpoint', application)
.then(response => {
res.status(200).send({ code: 200, success: true, message: response })
})
.catch(error => {
res.status(200).send({ code: 200, success: false, message: error })
});
})
If John and James submit form data from different browsers to my Express JS api, which is forwarded to another api, I need the respective responses to go back to the respective browsers...
Let's make clear for you, A response of a request will only send to the requester, But if you need to send a process request and send a response like, hey i received your request and you can use another get route to get the result sometimes later, then you need to determine which job you mean. So You can generate a UUID when server receives a process request and send it back to the sender as response, Hey i received your process request, you can check the result of process sometimes later and this UUID is your reference code. Then you need to pass the UUID code as GETparam or query param and server send you the correct result.
This is the usual way when you are usinf WebSockettoo. send a process req to server and server sends back a reference UUID code, sometime later server sends the process result to websocket of requester and says Hey this is the result of that process with that UUID reference code.
I hope i said clear enough.
As the title says, i have a part of my react app that tries to get some data from my database, making a select based on the value I passed to it. So im gonna go ahead and first show the code where i think the problem lies:
So first, this is the function from one of my forms that sends the request to the server, i know code is probably ugly, but i can tell from the console.logs that the parameters im sending are what i intend to send(a string called "licenciaInput"
async handleClickLicencia (event) {
event.preventDefault();
console.log(this.state);
console.log("licenciaInput: "+this.state.licenciaInput);
const datoBuscar = this.state.licenciaInput;
axios.get('http://localhost:3001/atletas/:licencia',this.state)
.then(response =>{
console.log(response)
})
.catch(error =>{
console.log(error)
})
And then, i have this function which is called in that localhost route which attempts to get "licencia", and launch a select in my postgresql db where licencia="whatever", you can see the sentence in the code:
const getAtletasByLicencia = (request, response) => {
const licencia = request.body.licenciaInput;
console.log("Request: "+request);
console.log("what the server gets: "+licencia);
// const licencia = request.licenciaInput;
const sentencia ="SELECT * FROM atleta WHERE licencia ='"+licencia+"'";
pool.query(sentencia, (error, results) =>{
if(error){
throw error
}
response.status(200).json(results.rows)
})
}
As you can see, i have console.logs everywhere, and i still cannot access whatever element i send, because i always get on the server console "undefined" value.
TLDR:How can i access the "licenciaInput" i passed from my client form to my server, i have tried request.body.licenciaInput, request.params.licenciaInput, and request.licenciaInput, but none of those seem to work
I also know i have to treat after that the data i receive from the server, but i need to solve this before looking two steps ahead. Im also really new to React and node/express, so feel free to burn me with good practices im not meeting.Thanks in advance
EDIT: Im also adding this code that i have which shows the route for my method in the server:
app.get('/atletas/:licencia', db.getAtletasByLicencia)
As #Gillespie59 suggested that i should send a POST request, but i dont think i should if im both trying to send a parameter to the server to make a select, and then send the results back to the client
Change your request to:
axios.get(`http://localhost:3001/atletas/${this.state.licenciaInput}`)
...
and your route (if you are using express) should look like this:
app.get('/atletas/:licencia', function (req, res) {
var licencia = req.params.licencia
...
})
As you are using request.body you should send a POST request with axios and add a body.
I want to update a document in Mongo, but when I send an Axios POST request to the server with params for the updates I receive nothing but a blank object on the server side - I'm using Node.js with an Express server (MERN stack).
I have tried the qs library module and Node's querystring module. I tried including headers with
'Content-Type': 'application/x-www-form-urlencoded' and 'application/json'.
My Axios POST request:
const A = 1;
const B = 2;
const data = { A, B };
console.log(qs.stringify(data)); // A=1&B=2
axios.post(url('upVote'), qs.stringify(data));
The server route:
app.post('/upVote', async (req, res) => {
console.log(req.params); // {}
await DB.updateVote(ID, collection, voteCount);
res.end();
});
The headers as shown by Chrome's DevTools.
... Also, all my axios.get() requests work fine and grab data from Mongo and send it back to my app properly, and the url/endpoints match.
There are a couple of ways to send data to the server with axios.
I see the confusion with the documentation in axios, I have not seen this usage before and it does seem to be broken upon looking at the request logs and object.
1) axios.post receives body of the request as a second parameter. So if you want to pass parameters to axios, you should do something like this:
const B = 2;
const data = { A: 1, B: 1 };
axios.post(url('upVote'), {}, { params: data });
Note that axios will handle stringification on it's own and that the third parameter is a config object.
On the server the params will be available at request.query
2) If you want to stringify the parameters yourself, then you should append them into your URL like so
axios.post(`url('upVote')?${qs.stringify(data)}`);
Same here, data on the server will be under request.query
3) It's generally better to use the body of the post request to transfer large data payloads for convenience. You should also consider what your caching strategies are and if they rely on request url without the consideration of request body it may be a concern.
axios.post(url('upVote'), data);
In this case data on the server will be under request.body
UPD: Originally forgot to mention that you will need a body-parser middleware to access request.body.
4) You can use axios without method shorthands which may be useful for some people
axios({
method: 'POST',
url: url('upVote'),
params: data
})
This is identical to the example in 1.
And all of them return a Promise which you can .then().catch() or await.
I think you want .body instead of .params.As you are sending data in body by post using axios. You are printing params which will print nothing for this url/api .
Try
console.log(req.body) // instead of req.params
If this did not work then please show us your react code.
Moreover
In react you have to add .then() after axios else it will say unhanded promise
To get params on server side you have to make some changes
In axios (react)
axios.post(url('upVote/param'), qs.stringify(data));
In server
app.post('/upVote/:params', async (req, res) => {
console.log(req.params)
.....
})
I think you are calling res.end(). I think it should be res.send(...)
This answer should help: https://stackoverflow.com/a/29555444/1971378
I send JSON POST data via a form in a MEAN environment to my server. On the server side, I process the data inside of a waterfall function, using the async library, including various operations such as:
[...]
- create a database entry for a new author
- create a database entry for a new book
- associate the new book to an author (reference to book ID)
[...]
This is the method called by my route, which handles the associated POST-request:
exports.createAuthor = function(req, res) {
console.log(req.url+' !!!POST REQUEST INCOMING!!! '+req.body);
async.waterfall([
function(callback){
//create Author db entry
},
function(parameter, callback){
//add author to additional directory (db action)
},
function(parameter, callback){
//create book db entry
},
function(parameter, callback){
//associate book to author (db action)
}
], function (err, result) {
console.log('DONE!!!');
res.send('200');
});
}
This is the client-side AngularJS controller code:
searchApp = angular.module("searchApp",[]);
searchApp.controller('authorCreator', function ($scope,$http) {
$scope.tags = [];
$scope.sendAuthor = function(){
alert('I was called!');
$http({
method: 'POST',
url: '/newauthor/',
data: { 'authorname' : $scope.authorName,
'authordescription' : $scope.authorDescr,
'bookname' : $scope.bookName,
'tags' : $scope.tags }
})
.success(function(data){
//no actions yet
})
.error(function(){
//no actions yet
});
};
});
This is the AngularJS form:
<div ng-controller="authorCreator">
<form>
<p>Author name: <input ng-model="authorName"></p>
<p>Author description: <input ng-model="authorDescr"></p>
<p>Book name: <input ng-model="bookName"></p>
<p>Tags:<input ng-model="tags"></p>
<p><button ng-click="sendAuthor()">Send</button></p>
</form>
</div>
I noticed that, if the waterfall-process is "stuck" somewhere, meaning the client does not get an answer to it's request whatsoever, the POST request seems to be sent a second time automatically (as soon as the browser is giving a timeout according to firebug). According to firebug, a second POST request does not seem to be sent by the browser, so the call must be initiated from somewhere else.
I found out by checking the database (multiple documents with identical values, except the ObjectID of course) and monitoring the node.js console window where I output incoming POST data. Again: as soon as the entire waterfall-process completes, hence the client browser does not abort the post request after a while, and res.send('200') executes, the error does not occur (= no multiple db entries).
Can anyone please tell me, who does initiate this second POST request and how may I deactivate it?
Cheers
Igor
Try adding this:
exports.createAuthor = function(req, res) {
if(req.method == 'POST' && req.url = 'REQUESTEDURL'){
console.log('POST REQUEST INCOMING!!! '+req.body);
async.waterfall([
//TODO...
]);
}
Maybe the problem is that the favicon or some other resource is doing a request to
After spending some time on that issue I found out, that this error seems to be based on missing answers to the client (be it via res.json, res.sendfile, ...). Therefore the client seems to re-send the request after some time, thus executing server-side code a second time. Responding to the client in reasonable time solves this issue. Sorry for the confusion.
i "fixed" this by adding
.get('/favicon.ico:1', (req, res) =>{
//do nothing because i dont care
})