Two awaits with try/catch - node.js

How can i resolve it? If the API call doesn't resolve, it doesn't enter the database call, and it ends up in the catch
router.get('/pokemons', async (req, res) => {
try {
const { name } = req.query;
const apiName = await axios.get(`https://pokeapi.co/api/v2/pokemon/${name}`)
if (apiName) {
return res.status(200).json({
data: apiName.data.abilities
});
}
const dbName = await Pokemon.findAll({
where: {
name
}
})
return res.status(200).json({
data: dbName
})
} catch (err) {
res.status(404).json({
message: "No existe Pokemon con ese nombre",
error: err
})
}
});

It seems https://pokeapi.co/api/v2/pokemon API is either not responding fast or having some issue. if you are not having more control over this API, you can
Set timeout for API call. if within that time period API does not respond, do further action.
OR Try Below Code:
router.get('/pokemons', async (req, res) => {
try {
const { name } = req.query;
let apiName = "";
try {
apiName = await axios.get(`https://pokeapi.co/api/v2/pokemon/${name}`);
}
catch (err) {
console.log(err)
}
if (apiName != "") {
return res.status(200).json({
data: apiName.data.abilities
});
}
const dbName = await Pokemon.findAll({
where: {
name
}
})
return res.status(200).json({
data: dbName
})
} catch (err) {
res.status(404).json({
message: "No existe Pokemon con ese nombre",
error: err
})
}
});

Related

TypeError: Cannot read properties of undefined (reading 'insertOne')

I had this error when I try to add a review using the curl command:
curl -X POST http://localhost:4444/api/v1/reviews/new -H “Content-Type:application/json” -d ‘{“movieId”:12,”user”:”sara”,”review”:”good”}’
reviews.controller.js
import reviewsDAO from "../dao/reviewsDAO.js";
export default class ReviewsController{
static async apiPostReview(req, res, next) {
try {
const movieId = parseInt(req.body.movieId)
const review = req.body.review
const user = req.body.user
console.log('movieId', movieId)
const reviewResponse = await reviewsDAO.addReview(
movieId,
user,
review
)
res.json({ status: "success" })
} catch (e) {
res.status(500).json({ error: e.message })
}
}
static async apiGetReview(req, res, next) {
try {
let id = req.params.id || {}
let review = await reviewsDAO.getReview(id)
if (!review) {
res.status(404).json({ error: "Not found" })
return
}
res.json(review)
} catch (e) {
console.log(`api, ${e}`)
res.status(500).json({ error: e })
}
}
static async apiUpdateReview(req, res, next) {
try {
const reviewId = req.params.id
const review = req.body.review
const user = req.body.user
const reviewResponse = await reviewsDAO.updateReview(
reviewId,
user,
review
)
var { error } = reviewResponse
if (error) {
res.status(400).json({ error })
}
if (reviewResponse.modifiedCount === 0) {
throw new Error(
"unable to update review",
)
}
res.json({ status: "success" })
} catch (e) {
res.status(500).json({ error: e.message })
}
}
static async apiDeleteReview(req, res, next) {
try {
const reviewId = req.params.id
const reviewResponse = await reviewsDAO.deleteReview(reviewId)
res.json({ status: "success" })
} catch (e) {
res.status(500).json({ error: e.message })
}
}
static async apiGetReviews(req, res, next) {
try {
let id = req.params.id || {}
let reviews = await reviewsDAO.getReviewsByMovieId(id)
if (!reviews) {
res.status(404).json({ error: "Not found" })
return
}
res.json(reviews)
} catch (e) {
console.log(`api, ${e}`)
res.status(500).json({ error: e })
}
}
}
I have tried several solutions but I didn't resolve the issue
reviewsDAO.js:
import mongodb from 'mongodb';
const ObjectID=mongodb.ObjectID;
let reviews;
export default class ReviewsDAO{
static async injectDB(conn){
if(reviews){
return
}
try{
reviews = await conn.db("reviews").collection("reviews");
} catch(e){
console.error(`Unable to establish collection handles in userDAO: ${e}..`);
};
};
static async addReview(movieId,user,review){
try{
const reviewDoc={
movieId:movieId,
user:user,
review:review
}
return await reviews.insertOne(reviewDoc);
}catch(e){
console.error(`Unable to post review: ${e}`);
return{error:e};
};
};
static async getReview(reviewId){
try{
return await reviews.findOne({_id:ObjectID(reviewId)})
}catch(e){
console.error(`Unable to get review: ${e}`);
return{error:e};
};
};
static async updateReview(reviewId,user,review){
try{
const updateResponse=await review.updateOne({_id:ObjectID(reviewId)},
{$set:{user:user,review:review}});
return updateResponse;
}catch(e){
console.error(`Unable to update review: ${e}`);
return{error:e};
};
};
static async getReviewByMovieId(movieId){
try{
const cursor=await reviews.find({movieId: parseInt(movieId)});
return cursor.toArray();
}catch(e){
console.error(`Unable to get review: ${e}`);
return{error:e};
};
};
};
reviews.route.js:
import express from 'express';
import ReviewsCtrl from "./reviews.controller.js";
const router=express.Router();
router.route("/movie/:id").get(ReviewsCtrl.apiGetReviews);
router.route("/new").post(ReviewsCtrl.apiPostReview);
router.route("/:id")
.get(ReviewsCtrl.apiGetReviews)
.put(ReviewsCtrl.apiUpdateReview)
.delete(ReviewsCtrl.apiDeleteReview)
export default router;
moviedb.js:
import app from './server.js';
import ReviewsDAO from "./dao/reviewsDAO.js";
import mongodb from 'mongodb';
import dotenv from 'dotenv';
const MongoClient=mongodb.MongoClient
dotenv.config();
const mongo_username = process.env.MONGO_USERNAME;
const mongo_password = process.env.MONGO_PASSWORD;
const port=4444;
MongoClient.connect(`mongodb+srv://${mongo_username}:${mongo_password}#cluster0.b5f7prn.mongodb.net/test`,
{
maxPoolSize: 50,
wtimeoutMS: 2500,
useNewUrlParser: true
})
.catch(err => {
console.error(err.stack)
console.error("Error connecting to the database:", err.message)
process.exit(1)
})
.then(async client => {
await ReviewsDAO.injectDB(client)
app.listen(port, () => {
console.log(`listening on port ${port}`)
})
})

How do i update in MongoDB with Node.JS

i have this code i am trying to write, the code is supposed to update the balance in MongoDB after properly computing the balance. The challenge is , it does not, it properly computes the balance, but updating the column for the user, it does not update. Looking out to see where and how to update the balances only I have not seen anything to help.
My code is Looking thus :
const router = require("express").Router();
const User = require("../models/User");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
router.post("/update-balance/:email", async (req, res) => {
try {
if (
!req.headers.authorization ||
!req.headers.authorization.startsWith("Bearer ") ||
!req.headers.authorization.split(" ")[1]
) {
return res.status(422).json({ message: "Please Provide Token!" });
}
const amount = parseInt(req.body.amount);
const user = await User.find({ email: req.params.email });
const balance = parseInt(user[0].balance);
//return balance;
//console.log(balance);
const total_amt = amount + balance;
//console.log(total_amt);
// update Balance
const wallet_user = new User();
try{
await wallet_user.updateOne({email : req.params.email}, {$set: {balance: total_amt}});
}catch(err){
console.log(err);
}
return res.send({ error: false, message: "OK" });
} catch (error) {
res.status(404).json({ message: error.message });
}
});
module.exports = router;
What Am I suppose to do that i am not doing rightly, kindly help.
The code above shows What I have attempted..
You can use $inc:
router.post('/update-balance/:email', async (req, res) => {
try {
if (
!req.headers.authorization ||
!req.headers.authorization.startsWith('Bearer ') ||
!req.headers.authorization.split(' ')[1]
) {
return res.status(422).json({ message: 'Please Provide Token!' });
}
const amount = parseInt(req.body.amount);
try {
await User.findOneAndUpdate(
{ email: req.params.email },
{ $inc: { balance: amount } }
);
} catch (err) {
console.log(err);
}
return res.send({ error: false, message: 'OK' });
} catch (error) {
res.status(404).json({ message: error.message });
}
});

Why do the property and the value disappear from the real database?

I try to console.log the user as below showing for the further manipulation of it but the weird thing is the places properties somehow disappeared, and if you check on the database, it's still there.
Anyone, please tell me what's wrong ...
const { validationResult } = require('express-validator');
const HttpError = require('../models/http-error');
const getCoordsForAddress = require('../util/location');
const PlaceSchema = require('../models/place_schema');
const UserSchema = require('../models/user_schema');
const { default: mongoose } = require('mongoose');
const { findById } = require('../models/place_schema');
const getPlaceById = async (req, res, next) => {
const placeId = req.params.pid;
let place;
try {
place = await PlaceSchema.findById(placeId);
} catch (err) {
const error = new HttpError('Somthing wehnt wrong, could not find a place', 500);
return next(error);
};
if (!place) {
const error = new HttpError('Could not find a place for the provided id.', 404);
return next(error);
} else {
res.json({ place: place.toObject({ getters: true }) });
};
};
const getPlacesByUserId = async (req, res, next) => {
const userId = req.params.uid;
let places;
try {
places = await PlaceSchema.find({ creator: userId });
} catch (err) {
const error = new HttpError('Something went wrong, couldn nott find the place', 500);
return next(error);
};
if (!places || places.length === 0) {
return next(
new HttpError('Could not find a place for the provided user id.', 404)
);
};
res.json({ places: places.map(p => p.toObject({ getters: true })) });
};
const createPlace = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log(errors);
return next(new HttpError('Invalid inputs passed, please check your data', 422));
};
const { title, description, address, creator, image } = req.body;
let coordinates;
try {
coordinates = await getCoordsForAddress(address);
} catch (error) {
return next(error);
}
const createdPlace = new PlaceSchema({
title,
description,
image,
location: coordinates,
address,
creator
});
// check if a exist userid is existing
let user;
try {
user = await UserSchema.findById(creator);
} catch (err) {
const error = new HttpError('Creating place failed, please try again.', 500)
return next(error);
};
if (!user) {
const error = new HttpError('Could not find user for provided id', 404)
return next(error);
}
try {
const sess = await mongoose.startSession();
sess.startTransaction();
await createdPlace.save({ session: sess });
user.places.push(createdPlace);
await user.save({ session: sess });
await sess.commitTransaction();
} catch (err) {
const error = new HttpError('Creating place failed, please try again.', 500);
return next(error);
};
res.status(201).json({ place: createdPlace });
};
const updatePlace = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log(errors);
return next(HttpError('Invalid inputs passed, please check your data', 422));
};
const { title, description } = req.body;
const placeId = req.params.pid;
try {
PlaceSchema.findByIdAndUpdate(placeId, {
title, description
})
} catch (err) {
const error = new HttpError('Somthing went wrong, could not update the place.', 500)
return next(error);
};
res.status(200).json({ place: updatedPlace.toObject({ getters: true }) });
};
const deletePlace = async (req, res, next) => {
const placeId = req.params.pid;
let thePlace;
let creator;
try {
thePlace = await PlaceSchema.findById(placeId);
creator = await UserSchema.findById(thePlace.creator);
} catch (err) {
const error = new HttpError('Somthing went wrong, could delete the place', 500);
return next(error);
};
console.log(creator);
try {
const sess = await mongoose.startSession();
sess.startTransaction();
await PlaceSchema.findByIdAndDelete(placeId, { session: sess });
await creator.places.pull(creator);
await UserSchema.save({ session: sess });
await sess.commitTransaction();
} catch (err) {
// console.log(err)
const error = new HttpError('Somthing went wrong, could delete the place', 500);
return next(error);
};
res.status(200).json({ message: 'Deleted place.' });
};
exports.getPlaceById = getPlaceById;
exports.getPlacesByUserId = getPlacesByUserId;
exports.createPlace = createPlace;
exports.updatePlace = updatePlace;
exports.deletePlace = deletePlace;
When console.log the user, there is no places of an array showing
But it's actually in the database, somehow it disappears when console.log

convert simple callbacks into async await

I am finding it hard to convert this user controllers code to async await. Can someone please help and guide me how can i do it too. So that i can also change any callbacks into async await.
Also if someone can provide a good source so that i can read about async await and how to apply them properly.
const User = require("../models/user")
exports.getUserById = (req, res, next, id) => {
User.findById(id).exec((error, user) => {
if (error || !user) {
return res.status(400).json({
error: "No user was found in DB"
})
}
req.profile = user
next()
})
}
exports.getUser = (req, res) => {
req.profile.salt = undefined;
req.profile.encrypted_password = undefined;
return res.json(req.profile)
}
exports.getAllUsers = (req, res) => {
User.find().exec((error, users) => {
if (error || !users) {
return res.status(400).json({
error: "No users was found in DB"
})
}
return res.json(users)
})
}
exports.updateUser = (req, res) => {
User.findByIdAndUpdate(
{ _id: req.profile._id },
{ $set: req.body },
{ new: true, useFindAndModify: false },
(error, user) => {
if (error) {
return res.status(400).json({
error: "You are not authorized to update this info"
})
}
user.salt = undefined;
user.encrypted_password = undefined;
res.json(user)
}
)
}
It should look something like this:
const User = require("../models/user");
exports.getUserById = async (req, res, next, id) => {
let user = await User.findById(id);
try {
if (!user) {
return res.status(404).json({
error: "No user was found in DB"
});
}
req.profile = user;
next();
} catch (err) {
return res.status(500).json({
error: "Something went wrong"
});
}
};
exports.getUser = (req, res) => {
req.profile.salt = undefined;
req.profile.encrypted_password = undefined;
return res.json(req.profile);
};
exports.getAllUsers = async (req, res) => {
let users = await User.find();
try {
if (users.length < 1) {
return res.status(404).json({
error: "No users was found in DB"
});
}
return res.json(users);
} catch (err) {
return res.status(500).json({
error: "Something went wrong"
});
}
};
exports.updateUser = async (req, res) => {
try {
let user = await User.findByIdAndUpdate(
{ _id: req.profile._id },
{ $set: req.body },
{ new: true, useFindAndModify: false }
);
user.salt = undefined;
user.encrypted_password = undefined;
return res.json(user);
} catch (err) {
return res.status(400).json({
error: "You are not authorized to update this info"
});
}
};
You should send back 404 errors if you cant find any user in the database. 400 means bad request.
You can achieve what you are asking by wrapping the function with Promise. In your example, you should use the solution given by Ifaruki, because mongoose already supports promises.
function waitSeconds(seconds) {
return new Promise(res => {
setTimeout(() => {
res();
}, seconds * 1000)
})
}
async function foo() {
console.log("Hello");
await waitSeconds(5);
console.log("World");
}
Here you can learn more about async in javascript

I'm getting a weird error while using "next-connect" in my nextJS project that had fixed itself in dev but is now even worse in prod

As i said in the title i am using a npm package called "next-connect" to structure my api. Every api route that i created suffered from this error. This is the error :
Unhandled rejection: TypeError: Cannot read property 'end' of undefined
at next (/var/task/node_modules/next-connect/lib/index.js:43:54)
at next (/var/task/node_modules/next-connect/lib/index.js:49:9)
at next (/var/task/node_modules/next-connect/lib/index.js:58:16)
at next (/var/task/node_modules/next-connect/lib/index.js:49:9)
at next (/var/task/node_modules/next-connect/lib/index.js:58:16)
at next (/var/task/node_modules/next-connect/lib/index.js:58:16)
at next (/var/task/node_modules/next-connect/lib/index.js:60:9)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
After a few minutes of trying i get to solve it in dev. Most of this due to messing with the .env file.
Here the code from my API Route :
import nextConnect from "next-connect";
import bcrypt from "bcryptjs";
import middleware from "../../middlewares/middleware";
const handler = nextConnect();
handler.use(middleware);
handler.get((req, res) => {
if (req.user) {
const { name, email, bio, profilePicture, emailVerified } = req.user;
return res.status(200).send({
status: "ok",
data: {
isLoggedIn: true,
user: {
name,
email,
bio,
profilePicture,
emailVerified
}
}
});
}
return res.status(200).send({
status: "ok",
data: {
isLoggedIn: false,
user: {}
}
});
});
handler.post((req, res) => {
const { email, password } = req.body;
return req.db
.collection("users")
.findOne({ email })
.then(user => {
if (user) {
return bcrypt.compare(password, user.password).then(result => {
if (result) return Promise.resolve(user);
return Promise.reject(Error("The password you entered is incorrect"));
});
}
return Promise.reject(Error("The email does not exist"));
})
.then(user => {
req.session.userId = user._id;
return res.send({
status: "ok",
message: `Welcome back, ${user.name}!`
});
})
.catch(error =>
res.send({
status: "error",
message: error.toString()
})
);
});
handler.delete((req, res) => {
delete req.session.userId;
return res.status(200).send({
status: "ok",
message: "You have been logged out."
});
});
export default handler;
And here code from the next-connect package (the one mentioned in the error report) :
module.exports = () => {
function connect(req, res) {
connect.handle(req, res);
}
connect.stack = [];
function add(method, ...handle) {
for (let i = 0; i < handle.length; i += 1) {
if (handle[i].stack) Object.assign(this.stack, handle[i].stack);
else this.stack.push({ handle: handle[i], method });
}
}
// method routing
connect.get = add.bind(connect, 'GET');
connect.head = add.bind(connect, 'HEAD');
connect.post = add.bind(connect, 'POST');
connect.put = add.bind(connect, 'PUT');
connect.delete = add.bind(connect, 'DELETE');
connect.options = add.bind(connect, 'OPTIONS');
connect.trace = add.bind(connect, 'TRACE');
connect.patch = add.bind(connect, 'PATCH');
// middleware
connect.use = add.bind(connect, '');
connect.error = add.bind(connect, 'ERR');
connect.apply = function apply(req, res) {
return new Promise((resolve) => this.handle(req, res, resolve));
};
connect.handle = function handle(req, res, done) {
let idx = 0;
const { stack } = this;
async function next(err) {
const layer = stack[idx];
idx += 1;
// all done
if (!layer) {
if (done) done();
else if (!res.headersSent) res.writeHead(404).end();
return;
}
// check if is correct method or middleware
if (layer.method !== '' && layer.method !== 'ERR' && layer.method !== req.method) {
next(err);
return;
}
try {
if (!err) { await layer.handle(req, res, next); return; }
// there is an error
if (layer.method === 'ERR' || layer.handle.length === 4) {
await layer.handle(err, req, res, next);
} else next(err);
} catch (error) {
next(error);
}
}
// Init stack chain
next();
};
return connect;
};

Resources