Node.js: POST request sent twice by system - javascript

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
})

Related

POST http://localhost:3000/updateSurvey 400 (Bad Request)

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.

Problem with React making Get request to Node(express)

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.

Node request() not being sent

I'm using the npm request library and am running into an issue where the request is never sent if I call express's res.send() after calling request. I realize the request callback won't fire if I close the connection, but I'm not even seeing the request being sent in the first place.
This code is being executed on RunKit (formerly TonicDev), an online code editor that allows code execution via endpoints. I'm not seeing this issue on my local machine, so it seems like it may have to do with RunKit. Anyone have any ideas as to what's going on here or how I might work around this?
You can execute the code yourself by going to:
https://runkit.com/gragland/58056bc6e9d9ed00130c84d5 and clicking the endpoint link at the top.
// Helper to return a RunKit compatible express app (runkit.com/tonic/express-endpoint)
var tonicExpress = require("#runkit/tonic/express-endpoint/1.0.0")
// Provide the exports object to the tonicExpress helper
var app = tonicExpress(module.exports)
var request = require('request')
app.get("/", function(req, res){
var request_number = 9
request({
// To see if request is sent go to: https://requestb.in/1coqbqn1?inspect
url: 'http://requestb.in/1coqbqn1',
method: 'POST',
json: {
request_number: request_number,
message: 'hello'
}
})
// The line below has to be commented out for the above request to be sent
// I don't care about the request callback() firing, I just want the request to be sent
res.send('Done')
})

Hide an API key (in an environment variable perhaps?) when using Angular

I'm running a small Angular application with a Node/Express backend.
In one of my Angular factories (i.e. on the client side) I make a $http request to Github to return user info. However, a Github-generated key (which is meant to be kept secret) is required to do this.
I know I can't use process.env.XYZ on the client side. I'm wondering how I could keep this api key a secret? Do I have to make the request on the back end instead? If so, how do I transfer the returned Github data to the front end?
Sorry if this seems simplistic but I am a relative novice, so any clear responses with code examples would be much appreciated. Thank you
Unfortunately you have to proxy the request on your backend to keep the key secret. (I am assuming that you need some user data that is unavailable via an unauthenticated request like https://api.github.com/users/rsp?callback=foo because otherwise you wouldn't need to use API keys in the first place - but you didn't say specifically what you need to do so it is just my guess).
What you can do is something like this: In your backend you can add a new route for your frontend just for getting the info. It can do whatever you need - using or not any secret API keys, verify the request, process the response before returning to your client etc.
Example:
var app = require('express')();
app.get('/github-user/:user', function (req, res) {
getUser(req.params.user, function (err, data) {
if (err) res.json({error: "Some error"});
else res.json(data);
});
});
function getUser(user, callback) {
// a stub function that should do something more
if (!user) callback("Error");
else callback(null, {user:user, name:"The user "+user});
}
app.listen(3000, function () {
console.log('Listening on port 3000');
});
In this example you can get the user info at:
http://localhost:3000/github-user/abc
The function getUser should make an actual request to GitHub and before you call it you can change if that is really your frontend that is making the request e.g. by cheching the "Referer" header or other things, validate the input etc.
Now, if you only need a public info then you may be able to use a public JSON-P API like this - an example using jQuery to make things simple:
var user = prompt("User name:");
var req = $.getJSON('https://api.github.com/users/'+user);
req.then(function (data) {
console.log(data);
});
See DEMO

node.js and hapi: fetching data from a database synchronously

Coming from a .net world where synchronicity is a given I can query my data from a back end source such as a database, lucene, or even another API, I'm having a trouble finding a good sample of this for node.js where async is the norm.
The issue I'm having is that a client is making an API call to my hapi server, and from there I need to take in the parameters and form an Elasticsearch query to call, using the request library, and then wait for the instance to return before populating my view and sending it back to the client, problem being is that the request library uses a callback once the data is returned, and the empty view has long been returned to the client by then.
Attempting to place the return within the call back doesn't work since the EOF for the javascript was already hit and null returned in it's place, what is the best way to retrieve data within a service call?
EX:
var request = require('request');
var options = {
url: 'localhost:9200',
path: {params},
body: {
{params}
}
}
request.get(options, function(error, response){
// do data manipulation and set view data
}
// generate the view and return the view to be sent back to client
Wrap request call in your hapi handler by nesting callbacks so that the async tasks execute in the correct logic order. Pseudo hapi handler code is as following
function (request, reply) {
Elasticsearch.query((err, results) => {
if (err) {
return reply('Error occurred getting info from Elasticsearch')
}
//data is available for view
});
}
As I said earlier in your last question, use hapi's pre handlers to help you do async tasks before replying to your client. See docs here for more info. Also use wreck instead of request it is more robust and simpler to use

Categories