Express app, multiple POST requests from the client side crashing page - javascript

I have a to-do list app that updates a string in a mongodb database with every change in state of the to-do list - that string is parsed on reload to render the state. It works great, except when I trigger 5 or 6 state changes quickly in sequence, it hangs the page. As example, if I delete 5 tasks over the course of a couple seconds. I assume the problem is handling all those post requests, but maybe it's on the updating mongodb side? Is there a way to handle a lot of post request like that in a some sort of queue?
Client side:
function sendData(obj) {
fetch('/jsondata', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(obj),
}).catch(function (error) {
console.log(error);
});
console.log('db updated');
}
Here's the mongo side that runs when the POST request is requested from client...if it helps:
app.post('/jsondata', function (req, res) {
updateUserCache(currentUserEmail, JSON.stringify(req.body));
});
async function updateUserCache(email, newState) {
const foundUser = await user.findOne({
email: email,
});
foundUser.cachedState = newState;
const newDate = await Date.now();
foundUser.date = newDate;
await foundUser.save();
console.log('user cache has been updated');
}

It's hanging because you're never sending back a response from your backend code, and at some point the browser will stop making new connections to it.
So make sure you end the requests properly:
app.post('/jsondata', async function (req, res) {
await updateUserCache(currentUserEmail, JSON.stringify(req.body));
res.end();
});

Related

error: 405 Method Not Allowed Using Node.js

I'm building a Weather Journal application using Node, and I keep getting this error when the POST route code is getting executed. My GET function is executed well and I retrieve the data needed then this error stops the rest of the process(saving data/updating the UI/etc)..
here is the piece of code causing the problem:
async function postData(url="",data={}){
console.log(data);
const res= await fetch (url, { //this method not allowed idk why.
method: 'POST',
headers: {
'content-type':'application/JSON'
},
credentials: 'same-origin',
body: JSON.stringify(data)
});
try{
const finalData= await res.json();
console.log(finalData);
return finalData;
} catch(error) {
console.log("error", error);
}
}
Here is the server-side code after setting up express/cors/body-parser
app.listen(port, () => {
console.log(`Now listening on port ${port}`);
});
app.get('/all', function (req,res) {
res.send(projectData)
});
app.post('/add', function(req,res){
console.log(req.body);
newEntry={
date: req.body.date,
temp: req.body.temp,
content: req.body.content
}
projectData.push(newEntry);
});
I tried to use different pieces of code I found online on the same topic but it all ended up giving me the same error, tried googling as well but didn't really help. I'm also a beginner with node, app building, or working with servers so I'm really not sure if what I stated here is gonna make it clear for y'all to help.

How do I connect service to a Cloud Foundry app?

I'm new to IBM cloud and I'm trying to build an application where I can write a text, press a button and that text is analysed by the service tone analyser returning a JSON so I can show it.
I have created an instance of said service and I have connected it to my application (a toolchain) using the 'connections' tab on the service.
I also have this code on the app.js file on my app:
const ToneAnalyzerV3 = require('ibm-watson/tone-analyzer/v3');
const { IamAuthenticator } = require('ibm-watson/auth');
const toneAnalyzer = new ToneAnalyzerV3({
version: '2019-10-10',
authenticator: new IamAuthenticator({
apikey: [API key found in service credentials],
}),
url: [API url found in service credentials],
});
app.get('/', function(req, res) {
res.render('index');
});
app.post('/api/tone', async function(req, res, next) {
try {
const { result } = await toneAnalyzer.tone(req.body);
res.json(result);
} catch (error) {
next(error);
}
});
The problem is that when I make the following call on my javascript:
$.post( "/api/tone", {text: textInput}, function(data){
console.log(data);
});
I get the error: 500 (Internal Server Error).
Does anybody know what I am doing wrong?
The issue is that you are sending req.body to be analysed for tone. If you take a look at the API Docs - https://cloud.ibm.com/apidocs/tone-analyzer?code=node#tone - you will see that you only need to send
const toneParams = {
toneInput: { 'text': text },
contentType: 'application/json',
};
I doubt very much that req.body has a toneInput field, and if it does have contentType it may not be set to one of the allowable values.

How to listen to a webhook on a route inside another route?

I have an api which communicates with a third party service. This third party service uses two live server url's which it uses to asynchronously pass the actual response with of any kind of communication with the service - result and error back to my application using webhook. So I created a tunnel with ngrok and I also created two urls (http request listener i.e route) which receive the result/error from the service. Hence when I hit api 1, the actual response is passed in req.body to the listener 1 & 2. What now I need to figure out is if there is any way to pass this response from the webhook listener back to api 1, or if there is any way the async flow of my api 1 can keep going on by communicating directly with the webhook listener.
//Controller
const sendPaymentRequest = async (req, res) => {
try {
//Send payment request to 3rd party service
const endpoint = "/mpesa/b2c/v1/paymentrequest";
const url = MPESA_URL + endpoint;
const config = {
headers: {
Authorization: `Bearer ${access_token}`,
},
};
const body = {
Remarks: "Sending money from mobile wallet",
QueueTimeOutURL: "http://f815c811f619.ngrok.io/api/v1/b2c/error",
ResultURL: "http://f815c811f619.ngrok.io/api/v1/b2c/result",
};
const payment_reponse = await axios.post(url, body, config);
const { data } = payment_reponse;
console.log("Payment request => ", data); //Not the actual response
//*------------Need actual response from the listener in routes.js--------//
res.status(200).json({ message: "Send money request", data });
} catch (error) {
console.log("Error while making a payment request", error);
res
.status(400)
.json({ message: "Error while send payment request", error: error.data });
}
};
//Routes.js
this.router.post("/b2c/result", (req, res) => {
console.log(req.body); //Actual response from API-1
});
this.router.post("/b2c/error", (req, res) => {
console.log(req.body); //Error if any from API-1
});
I don't think you can wait for the webhook call inside the api 1 block.
You could persist this request in a database, and when the payment API calls your webhook can query your database for information about the original request and process the information based on that.

Redirect and send data from Node server back to React

I have a NodeJS server in which I'm using Express and a front-end with React. I want to know how to send data from the server to the front-end. All the solutions I've seen use a call from the front-end, then the server answers, and finally the front-end gets the data. My problem is that I don't have a call from the front-end, but a call back-end (router.get('/callback')) to back-end (router.get('/receipt/:id')). Here is the code for a better understanding.
router.get('/callback', (req,res) => {
const ref = req.query.reference;
verifyPayment(ref, (error,body)=>{
if(error){
//handle errors appropriately
console.log(error)
return res.redirect('/payment/error');
}
response = JSON.parse(body);
const data = _.at(response.data, ['reference', 'amount','customer.email', 'metadata.full_name']);
[reference, amount, email, full_name] = data;
newDonor = {reference, amount, email, full_name};
const donor = new Donor(newDonor);
donor.save().then((donor)=>{
console.log("--------------- donor" + donor);
if(!donor){
return res.redirect('/payment/error');
}
res.redirect('/payment/receipt/' + donor._id);
}).catch((e)=>{
res.redirect('/payment/error');
});
});
});
router.get('/receipt/:id', (req, res)=>{
const id = req.params.id;
Donor.findById(id).then((donor)=>{
if(!donor){
res.redirect('/payment/error')
}
// I'VE TRIED THIS
//res.redirect('http://localhost:3000/#' + donor.full_name);
/*
AND THIS
console.log(donor.full_name);
const resp = axios.post('http://localhost:3000', {params: {donor.full_name}});
console.log(resp.data);
*/
}).catch((e)=>{
res.redirect('/payment/error')
});
});
Now what I want is to come back to the front-end (a index.js using React) and get the data and show it. Any idea?????
You need to understand how the data pass between the Node server and your React App.
We use JSON objects to pass the data server to the client (look for REST APIs for more info)
Try this in your server
router.get('/receipt/:id', (req, res)=>{
const id = req.params.id;
Donor.findById(id).then((donor)=>{
if(!donor){
res.redirect('/payment/error')
}
//How to send the data
res.status(200).json({
message: "Data returned Successfully",
Fullname:"donor.full_name"
});
}).catch((e)=>{
res.redirect('/payment/error')
});

How to read data from POST, test it with a condition and send a response back

I'm looking for an easy solution to front-end and back-end communication.
I want to write simple JS front-end client where a user can put a number between 1 an 10 000 to guess the number that server has generated.
So the client job is to send number that user is guessing. The server should test if secretNumber is higher or lower then that provided by the user and it should send back that info.
For now, my server only sends that secret number. I'm getting it inside my client console, so the connection is working.
My question is how should I modify my server code to read the number value from request, test it and then send the right response (example -> your number is higher than the secretNumber)?
This is my server:
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors());
app.use((request, response, next) => {
console.log(request.headers);
next();
});
app.use((request, response, next) => {
request.secretNumber = Math.floor(Math.random() * 10000) + 1;
next();
});
app.get('/', (request, response) => {
response.json({
secretNumber: request.secretNumber
});
});
app.listen(3001, () => console.log("Listening on 3001"));
Here is my front-end JS code (I'm using axios):
export function guessNumber(guessValue) {
return dispatch => {
dispatch({ type: GUESS_NUMBER });
axios
.post('/guess', {
isNumber: guessValue,
})
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});
};
}
And I was here looking for answer, but maybe I'm to inexperiened and I need some real example...
First you need to persist the secretNumber between requests. At the moment you are generating a new value on each request.
Assuming just one client using the backend concurrently, you can do this by generating the secretNumber when the server starts and keep it in memory (assign it to a variable).
Then you can simply use route params to capture the client's guess:
app.get('/guess/:guess', (request, response) => {
const guess = params.guess;
// compare guess with secretNumber and respond accordingly
});
Alternatively you can use the request's body (https://expressjs.com/en/4x/api.html#req.body) instead of route params.

Categories

Resources