Send data from React Native front end to Express back end - javascript

I'm new to React and building a MERN stack. I'm having issues passing a variable from my front end to my back end. I've tried using console logs to debug and I can see that my request body is coming up blank. I've spent hours trying to figure out what I'm doing wrong but I haven't had any breakthrough yet.
Please see my code below.
User Frontend Hook
const fetchUser = (dispatch) => {
return async () => {
const email = await AsyncStorage.getItem("email");
console.log("async email:", email);
try {
console.log("sending email:", email);
const userInfo = await trackerApi.get("/users", {email});
dispatch({ type: "fetch_users", payload: userInfo.data });
} catch (err) {
console.log(err);
}
};
};
Express/Axios Backend
router.get("/users", async (req, res) => {
console.log("Request Body:", req.body);
try {
const { email } = req.body;
// console.log("Email for req: ", email);
const user = await User.find({ email: email });
console.log("Users for req: ", user);
res.send(user);
} catch (err) {
console.log(err);
}
});

The issue is related to the HTTP method, your route/API is GET call and get method does not have the body, either update to post or use req.query.
Client
const userInfo = await trackerApi.post("/users", {email});
// OR
const userInfo = await trackerApi.post("/users", { data: {email});
Server
router.post("/users", async (req, res) => {

Related

Code continuing after response already sent

I am trying to write a test for sending a 404 error whenever a blog is posted without a token and I keep getting "TypeError: Cannot read properties of undefined (reading '_id')". I know this is because my user variable is null which is due to there being no token sent with the request. Shouldn't the code stop reading after the response is sent? Or is there another way to counteract this? User will only be defined when a token is sent with the request. I can sort of solve this by using if/else statements to only use code if the user var is defined but is there a more effective way? Any help would be greatly appreciated.
const blogRouter = require('express').Router();
const req = require('express/lib/request');
const Blog = require('../models/blog')
const User = require('../models/user')
const jwt = require('jsonwebtoken');
const { default: mongoose } = require('mongoose');
const { decode } = require('jsonwebtoken');
require('dotenv').config()
blogRouter.post('/', async (request, response) => {
console.log("Request body of blog is",request.body)
var user = request.user
console.log("User is", user)
try{
const decodedToken = jwt.verify(request.token, process.env.SECRET)
console.log("decodedToken is", decodedToken)
}
catch(err){
if(!request.token || !decodedToken.id){
console.log("got in the catch block")
response.status(401).json({error: "token missing or invalid"})
}
else {
console.log(err)
}
}
const body = request.body
const newBlog = new Blog({
title: body.title,
author:body.author,
url: body.url,
likes: body.likes,
user: user._id // Error here because user is null
})
console.log("newBlog is",newBlog)
if (newBlog.title == null && newBlog.url == null){
response.status(400)
response.end()
}
else{
newBlog.save()
user.blog = user.blog.concat(newBlog._id)
user.save()
.then(result => {
console.log("Saved to database!!!!!")
response.status(201).json(result)
})
.catch(error => {
console.log("Could not save to database")
})
}
})
module.exports = blogRouter

How to handle 401 error status code error in Node.js/Express?

I am working on login functionality in my project, now, flow looks like this (from front-end to back-end):
async login() {
await login({
password: this.userPassword,
login: this.userLogin,
twoFactor: this.twoFactor
}).then((res) => {
if (res.error) {
//
} else {
console.log(res)
}
})
}
And here is starts problems, as you can see if something goes wrong, I return status code 401 and some error message. When I login with correct data, there is no problem with getting token, but when I provide wrong data I have external pending login endpoint in development tools in browser and then, after some time, Error: Request failed with status code 401 in front end terminal. Without this status(401) with just JSON it works fine, but when I try to add 401 code, application crashes.
const userService = require('./../services/userService')
const crypto = require('./../services/cryptoService')
const jwt = require('./../services/jwtService')
const twoFactorService = require('node-2fa')
module.exports = {
login: async (req, res) => {
let { login, password, twoFactor } = req.body
password = crypto.encrypt(password, process.env.APP_KEY)
const result = await userService.getUserToLogin(login, password)
if (!result) {
res.status(401).json({
error: 'Unauthorized'
})
} else {
const faCode = result.twofatoken
const result2F = twoFactorService.verifyToken(faCode, twoFactor);
if ( !result2F || result2F.delta !== 0 ) {
res.status(401).json({
error: 'Unauthorized'
})
} else {
const userId = crypto.encrypt(result.id, process.env.CRYPTO_KEY)
const token = await jwt.sign({
uxd: userId,
});
res.json(token);
}
}
}
}
Actually, I have no idea on what to do with that and how to handle this error.
Ok, here is the answer. Actually, you just need to handle this error in your router:
router.post('/login', async (req, res) => {
try {
const data = await api.post('/login', req.body)
res.json(data.data)
} catch (e) {
// Probably you have here just console.log(e), but this way, you can handle it
res.status(e.response.status).json(e.response.data)
}
})

Can't save() the same doc multiple times in parallel and Operation `users.insertOne()` buffering timed out after 10000ms

This is my router code :
router.post('/users/register',async (req,res) => {
console.log(req.body);
const user = new User(req.body);
try{
await user.save(function(err){
if (err) {
console.log(err);
}
});
const token = await user.generateAuthToken();
res.redirect('/');
}catch(e){
console.log(e);
res.status(400).send(e);
}
});
Generate Token Code :
userSchema.methods.generateAuthToken = async function() {
const user = this;
const token = jwt.sign({ _id : user._id.toString() },process.env.JWT_SECRET_CODE);
user.tokens = user.tokens.concat({token});
await user.save();
return token;
}
user saving code:
userSchema.pre('save', async function (next){
const user = this;
if(user.isModified('password')){
user.password = await bcrypt.hash(user.password,8);
}
next();
});
Error :
ParallelSaveError: Can't save() the same doc multiple times in parallel. Document: 61109ecdc48220245c0ecaf7
at model.Model.save
at model.userSchema.methods.generateAuthToken
MongooseError: Operation `users.insertOne()` buffering timed out after 10000ms
at Timeout.<anonymous>
This is the data I'm sending to mongo database :
{
name: 'sdhfie',
username: 'eifh_2397',
email: 'example#gmail.com',
phone: '+918329389241',
password: 'sdfieu#92734',
'repeat-password': 'sdfieu#92734'
}
I consoled the data and Data is sent but user is not saved.
I had tried most of the solutions available on stackoverflow but nothing worked in case of mine. Please try helping me out.
You are currently mixing async and callback. Try updating POST handler to remove the callback function from save():
router.post('/users/register', async (req,res) => {
console.log(req.body);
const user = new User(req.body);
try {
await user.save();
const token = await user.generateAuthToken();
res.redirect('/');
} catch(e){
console.log(e);
res.status(400).send(e);
}
});
Hopefully that helps!

How do I correctly await the return of an async function in javascript?

I'm currently working on a Google Sign-in Auth app with a React frontend and an Express backend and I'm currently stuck in the part of the process where I'm validating tokens on the backend. The docs for this process show this code to validate the token:
const {OAuth2Client} = require('google-auth-library');
...
const client = new OAuth2Client(CLIENT_ID);
async function verify() {
const ticket = await client.verifyIdToken({
idToken: token,
audience: CLIENT_ID, // Specify the CLIENT_ID of the app that accesses the backend
// Or, if multiple clients access the backend:
//[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
});
const payload = ticket.getPayload();
const userid = payload['sub'];
// If request specified a G Suite domain:
//const domain = payload['hd'];
}
verify().catch(console.error);
I've implemented this code in my own project here:
//verify token
async function verify(token, client) {
const ticket = await client.verifyIdToken({
idToken: token,
audience: keys.google.clientID,
});
const payload = ticket.getPayload();
const userid = payload['sub'];
const domain = payload['hd'];
const email = payload['email']
console.log('User ID: ' + userid);
console.log('Domian: ' + domain);
console.log('Email: ' + email);
var message = '';
var cookie = {};
await User.find({email: email}, (error, user) => {
if(error) {
message = error;
} else if (user.length === 0) {
message = 'this user is not in the database';
} else {
message = 'this user is in the database';
const session = new Session({
email: email,
session_token: token
});
cookie = {
email: email,
session_token: token
};
session.save((error, session) => {
if (error) {
console.log(error);
} else {
console.log('session saved');
}
});
console.log(message);
}
});
return Promise.resolve(cookie);
}
//recieve token id from frontend, verify it, and send session back in response
router.post('/google', (req, res) => {
const body = req.body.tokenID;
const client = new OAuth2Client(keys.google.clientID);
let cookie = verify(body, client).catch(console.error);
console.log('Cookie:' + cookie);
return res.send(cookie);
});
Currently when this runs everything inside the async function executes, but the return statement only returns the empty promise object. I think I'm making a mistake using async and await incorrectly, but I don't know how to correctly get the function to wait for all the work verifying the token and then update the DB before returning.
Not sure if this will help, but when I call the route my console gives me this output:
(I took out my personal info from the output fields, but assume these lines actually have gmail account info)
...
Cookie:[object Promise]
User ID: <GOOGLE ID>
Domian: <DOMAIN>
Email: <USER EMAIL>
this user is in the database
session saved
Thanks for reading!
Since "verify" function is an async function, you should add "await" before calling it. For catching errors you can simply place it in a try/catch:
router.post('/google', async (req, res) => {
const body = req.body.tokenID;
const client = new OAuth2Client(keys.google.clientID);
try {
let cookie = await verify(body, client);
console.log('Cookie:' + cookie);
return res.send(cookie);
} catch(error) {
// handling error
console.log(error);
return res.send("error")
}
});
`
You're mixing async/await with callback based calls. I don't know the internals of the library you're using, but the pattern should look more like this:
var cookie = {};
try{
const user = await User.find({email: email});
if (user.length === 0) {
console.log('this user is not in the database');
}
else {
console.log('this user is in the database');
const session = new Session({
email: email,
session_token: token
});
try{
await session.save();
console.log('session saved');
} catch(err){
console.log(err);
}
return {
email: email,
session_token: token
};
} catch(error){
console.log(error);
}

Getting single message from Graph

I'm trying to get a single email from an Office 365 Mailbox.
I'm sending the email id to my app via a POST (req.body.id) and then calling this code in order to get some email properties:
router.post('/id', async function(req, res, next) {
console.log("email with ID -> ", req.body.id)
let parms = { title: 'Inbox', active: { inbox: true } };
const accessToken = await authHelper.getAccessToken(req.cookies, res);
const userName = req.cookies.graph_user_name;
if (accessToken && userName) {
parms.user = userName;
// Initialize Graph client
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
try {
const result = await client
.api('/me/messages/', req.body.id)
.select('id,subject,from,toRecipients,ccRecipients,body,sentDateTime,receivedDateTime')
.get();
parms.messages = result.value;
console.log("email -> ", result.value);
res.render('message', parms);
} catch (err) {
parms.message = 'Error retrieving messages';
parms.error = { status: `${err.code}: ${err.message}` };
parms.debug = JSON.stringify(err.body, null, 2);
res.render('error', parms);
}
} else {
// Redirect to home
res.redirect('/');
}
});
At the moment, result.value contains all of the messages in the mailbox instead of just the message with provided id.
Could someone tell me where my error is, please?
The api method has a single path parameter. Calling it like .api('/me/messages/', req.body.id) is effectivly sending it a path ("/me/messages/") along with an additional parameter it ignores.
You need to send it a single string so you'll need to append the req.body.id to the path ({path} + {id}):
const result = await client
.api('/me/messages/' + req.body.id)
.select('id,subject,from,toRecipients,ccRecipients,body,sentDateTime,receivedDateTime')
.get();

Categories

Resources