I am trying to create signup and Login for the first time with express and react using PostgreSQL. My post works just fine. A user can be added to the database so I jumped into handling duplicates.
I am using the findUserByEmail function to find my email and then, in my routes, create the user if it does not exist.
I tried everything and still is giving me problems. I manage to get it working by just returning the query, without a response, which I don't think is right:
const findUserByEmail = (req, response) => {
return pool.query("SELECT * FROM users WHERE email = $1", [req.body.email])
};
Although, I need the response to handle the errors.
The way that I found more common and is how I am trying is:
const findUserByEmail = (req, response) => {
pool.query("SELECT * FROM users WHERE email = $1", [req.body.email]),
(error, results) => {
if (error) {
throw error;
}
response.json(results.rows);
};
};
And when I call it here:
app.post("/signup/user", (req, res, next) => {
queries
.findUserByEmail(req, res)
.then(user => {
if (user.rows.length > 0) {
res.status(400).send("this email is already in use");
} else {
queries.createUser(req.body, res);
}
})
.catch(err => {
console.log(err);
res.status(500).send("Something went wrong");
});
});
But the error is:
Cannot read property 'then' of undefined
If anybody can give me a hand cause I've been 2/3 weeks just for the authentication.
I'll leave my repo if anybody wants to have a look, is a bit messy though.
https://github.com/jaitone/CRUD-in-JS
Thank you!
if you are using pg as part of your project. then:
const findUserByEmail = (req, response) => { // send just email instead
return pool.query("SELECT * FROM users WHERE email = $1", [req.body.email])
};
Is completely legal and beautiful. The library creates a promise and returns it.
I manage to get it working by just returning the query
It is not returning the query, it is returning the mechanism to run the query in a promise wrapper(to be run in the future). So when you do .then it will actually execute and return the result. BUT
If you want to do it manually:
In the findUserByEmail you are not returning a Promise, instead you are just ending the request chain by saying res.json(which in turn means you are returning undefined).
You can create a Promise wrapper or use util.promisfy to make the pool.query a promise.
const findUserByEmail = (req, response) => { // send just email instead
return new Promise((resolve, reject)=>{
pool.query("SELECT * FROM users WHERE email = $1", [req.body.email]),
(error, results) => {
if (error) {
reject(error);
}
resolve(results.rows);
};
});
};
Note, sending the email instead of whole req and res objects is a good idea.
Related
I am using this <res.write()> ==> https://nodejs.org/api/http.html#responsewritechunk-encoding-callback (in nodejs)
and using this fetch ==> https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
My situation is that I didn't see any response when using the res.write() function inside of the fetch function. for example, in the below backend code, I tried to put res.write("456") inside of the first then function below fetch, but I only see 123 returned in the frontend, no 456.
res.write("123");
fetch('http://example.com/movies.json')
.then((response) => {response.json(), res.write("456")})
.then((data) => console.log(data));
I have searched Google for a while, but didn't see anything related. My guess is that this could be because of async usage.
appreciate if someone can give suggestions.
===== update =====
res is express's res obj
async sendText(res: Response){
res.write("123")
fetch('http://example.com/movies.json')
.then((response) => {return response.json()})
.then((data) => {
console.log(data);
res.write('456');
res.end();
});
}
seeing behavior: only see 123 in the frontend.
VS
async sendText(res: Response){
res.write("123")
await fetch('http://example.com/movies.json')
.then((response) => {return response.json()})
.then((data) => {
console.log(data);
res.write('456');
res.end();
});
}
seeing behavior: can see both 123 and 456 in the frontend.
I never use await and .then together before, not fully understand the difference. searching the web rn.
You aren't checking for any errors or an unsuccessful response so response.json() may be failing, preventing anything after it from executing.
Something like this should work better for you
async sendText (res: Response) {
res.write("123");
const response = await fetch("http://example.com/movies.json");
// check for an unsuccessful response
if (!response.ok) {
const error = new Error(`${response.status} ${response.statusText}`);
error.text = await response.text();
throw error;
}
const data = await response.json();
res.write("456");
res.end(); // finalise the HTTP response
console.log(data); // log data for some reason ¯\_(ツ)_/¯
};
This will return a promise that resolves with undefined or rejects with either a networking error, HTTP error or JSON parsing error.
When calling it, you should handle any rejections accordingly
app.get("/some/route", async (res, res, next) => {
try {
await sendText(res);
} catch (err) {
console.error(err, err.text);
next(err); // or perhaps `res.status(500).send(err)`
}
});
I never use await and .then together before
Nor should you. It only leads to confusing code.
I am working on API Get request. I have created a POST request to add the data in firebase realtime database. The code is as follows:
// CREATE POST
app.post("/post", (req, res) => {
let key;
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in.
var newPost = firebase.database().ref("posts/");
var myPost = newPost.push({
createdBy: user.uid,
from: req.body.from,
to: req.body.to,
duration: req.body.duration,
comments: req.body.comments,
});
res.send(newPost);
const postId = myPost.key;
console.log(postId);
} else {
// No user is signed in.
res.status(404).send("No user is signed in right now!");
}
});
});
Now, in order to get a specific post, I have written the following code:
// GET SPECIFIC POST
app.get("/post/:id", (req, res) => {
let response;
firebase
.database()
.ref("posts/" + req.params.id)
.on("value", (snapshot) => {
response = snapshot.val();
});
res.send(response);
});
I am new at Firebase, so I dont really know how to get a specific post. Please help me out
Calls to Firebase are asynchronous, because they require a call to the server. While that call is happening, your main code continues. And then when the data is available, your callback is invoked with the data from the server.
Right now your res.send(response) runs before the response = snapshot.val() is ever called. The rule with asynchronous APIs is simple: any code that needs the data needs to be inside the callback, or be called from there.
So in your case:
app.get("/post/:id", (req, res) => {
firebase
.database()
.ref("posts/" + req.params.id)
.once("value")
.then((snapshot) => {
res.send(snapshot.val());
});
});
You'll note that I also change from on to once, since you only care about getting the value once (instead of attaching a permanent listener that monitors the database for changes).
Dealing with asynchronous API is a common stumbling block, so I recommend spending some time reading these answers to learn more:
Why Does Firebase Lose Reference outside the once() Function?
Firebase response is too slow
Best way to retrieve Firebase data and return it, or an alternative way
I simply did this:
app.get("/post/:id", (req, res) => {
var key = req.params.id;
console.log(key);
firebase
.database()
.ref("posts")
.child(key)
.get()
.then((snapshot) => {
res.send(snapshot.val());
});
});
this solved the problem
I am using Knex JS for user authentication in order to get email and password from the user and connect to PostgreSQL to check for authentication.
router.post('/login', async (req, res) => {
knex.select('email','password').from('users')
.where('email', '=',req.body.email)
.then((data) => {
const isValid = bcrypt.compareSync(req.body.password, data[0].password);
if (isValid === true) {
res.render('index-v1');
}
});
});
But the render function is not rendering the index ejs file but rather the localhost is not responding.
Thanks in advance for the help.
So, as the comments suggest, there are two possible paths not covered by your route, which is apparently leading to a lack of response from the server. Remember, if you don't tell it to respond (with res.render or similar) it won't respond, leaving your client hanging.
router.post('/login', async (req, res) => {
try {
const data = await knex.select('email', 'password')
.from('users')
.where('email', '=', req.body.email)
const isValid = bcrypt.compareSync(req.body.password, data[0].password);
if (isValid) {
res.render('index-v1');
return
}
res.render('error-page');
} catch (e) {
res.render('error-page');
}
});
In other words: if the password is incorrect, we still need to respond to the client. If there's some kind of database error (or the user doesn't exist, say) we still need to respond to the client. Exactly how you respond is of course up to you, but that's the kind of structure you need to think about.
The Problem
I deployed a create-react-app webapp to aws ec2. It's used to display data from a database and send data to it. I use ExpressJS, CORS and MySQL.
With the following code i fetch the corresponding URL and the server.js sends back the database content. Until here, everything works fine.
getBets = _ => {
fetch("http://ec2***.amazonaws.com
.then(response => response.json())
.then(response => this.setState({bets: response.data}))
.catch(err => console.error(err))
};
The problem begins when sending data to the database with the following code:
addBet = _ => {
const { bet } = this.state;
fetch(`http://ec2***.amazonaws.com/bets/add?name=${bet.person_name}&bet=${bet.time_bet}`)
.then(response => response.json())
.then(this.getBets)
.catch(err => console.error(err))
};
On click the addBet-function populates the db, but in chrome I following error:
GET http://ec2***.amazonaws.com/bets/add?name=Peter%20Pan5&bet=10:17%205 net::ERR_EMPTY_RESPONSE
and
TypeError: Failed to fetch
Regarding chrome dev-tools, the first error corresponds to the fetch in the addBet function and the second error to the catch part.
On the server side I've the following code for processing the fetch:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES("${name}", "${bet}", CURTIME())`;
connection.query(INSERT_BET, (err, res) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I want to mention, that the res paramter in the app.get part is unused. That tells me my IDE.
After a lot of hours digging deeper in the topics of expressJS and the fetch api, I guess, that the app.get part doesn't send a response to the server. But the fetch need some response.
My Question
How do I have to change the code in the app.get part to send a proper response back to the server?
AND
Am I right with my guess?
In MYSQL when you do an insert query you get back err,results and fields in the callback function like this:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function (error,
results, fields) {
if (error) throw error;
console.log(results.insertId);
});
You have used the parameter res for result and then you have used res.send() which now corresponds to that res parameter in the callback function and not the res object.Rewrite it like this:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES(?,?,?)`;
connection.query(INSERT_BET,[name,bet,CURTIME()] ,(err, result) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I have also used prepared statement in place of normal sql queries. These are used to prevent sql injections. I hope it will work now.
I get this error #Can't set headers after they are sent# when using dbquery multiple times.
Hi, I'm almost new to node.js and I can't figure out why this error appears. If I try with one dbquery then everything is ok. But if I use multiple query then it crashes.
router.get(
'/auth/facebook/token',
(req, res, next) => {
passport.authenticate('facebook-token', (error, user, info) => {
if (user){
myDB.setUser(user.email,(err,pinfo) =>{
if (err) {
res.send(err);
}
else {
res.send(pinfo); <- Crash at this line!!!
}
});
}
next();
})(req,res, next);
}
);
function setUser (email, cb) {
pool.query("INSERT INTO users (email,pinfo) VALUES (?,0)", email, (err, result) => {
if(err){
cb(err);
return;
}
else{
pool.query("SELECT pinfo FROM users WHERE email = ?", email,(err,pinfo) =>{
cb(err,pinfo);
});
}
});
}
You are calling next middle layer function using next(). After sending the response to the user. Try without next or modify your logic to. Hope this will help you
once you are used res.send you cannot use it again
it seems you are sending a response at two positions please check the logic thoroughly
Some Where you sending response twice and hence this error. R.sarkar is right take out next() call and add it somewhere you will want to continue with your next dbquery or else respond from top function only once and never call next().