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
Related
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}`)
})
})
I am New To async/await coding in node js. I am trying to fetch data from mysql and then populate the result into an object. But i am not finding a way how to do it in controller.js file.
My source code similar to this.
My Router File
const express = require("express");
const controller = require("controller");
const router = express.Router();
router.route("/").get(controller.findAll);
My Controller File
const model = require("model");
exports.findAll = async (req, res) => {
const all = model.getAll((err, data) => {
if (err) {
res.status(500).send({
message: err.message || "Some error occurred while retrieving data.",
});
}
return data;
});
const user = model1.getUser((err, data) => {
if (err) {
res.status(500).send({
message: err.message || "Some error occurred while retrieving user.",
});
}
return data;
});
// somefunctionality(all, user);
// res.send(result);
};
My Model file
const con = require("./db");
// constructor
const Customers= function (customer) {
this.id = customer.id;
this.first_name = customer.first_name;
this.last_name = customer.last_name;
this.email = customer.email;
};
Customers.getAll = () => {
const query = `SELECT * FROM doctors`;
sql.query(query, (err, res) => {
if (err) {
console.log("error: ", err);
result(null, err);
return;
}
console.log("customers: ", res);
result(null, res);
};
user model same as customer
Thanks for your help
The first thing I would do is covert your Customers.getAll method to return a promise:
model file
Customers.getAll = () => {
const query = `SELECT * FROM doctors`;
return new Promise((res, rej) => {
sql.query(query, (err, data) => {
if (err) {
console.log("error: ", err);
rej(err);
return;
}
console.log("customers: ", res);
res(data);
})
};
(Note that you'll probably have to do something similar to the getAll method for your User model)
Now, in the controller, you can use try/catch to handle any errors.
*controller file
exports.findAll = async (req, res) => {
try {
const all = await model.getAll();
const users = await model1.getUser();
const result = somefunctionality(all, user);
res.send(result);
} catch(err) {
res.status(500).send({
message: err.message || "Some error occurred while retrieving data.",
});
}
};
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
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;
};
the question is pretty self explanatory. I am registering/signing up users in a mongoDB database. They are being registered fine and an accesstoken [jwt based] is also being generated.
Now, when I go to query the database to fetch the list of users I am getting that error -
jwt is not defined.
It is worthwhile to mention that users also in my backend can have two type of roles - basic and admin. And only an admin user can fetch list of all users by sending accessToken in the header as Bearer authorization parameter.
I have 2 main files in my backend project structure that uses jwt.access methods like jwt.verify or jwt.signIn; these are the server.js and userController.js [a separate file where I have written all individual db related methods].
As far as I am concerned, all necessary packages are there in my project - express, node, jwa, jws, jsonwebtoken, mongo, mongoose, bcrypt, cors etc. So what is the trouble?
My route.js -->
const User = require('../models/user.model');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const { roles } = require('../models/roles');
const JWT_SECRET = "$#GR24T4344$#$##%ETWWTEME%$6";
async function hashPassword(password) {
return await bcrypt.hash(password, 10);
}
async function validatePassword(plainPassword, hashedPassword) {
return await bcrypt.compare(plainPassword, hashedPassword);
}
exports.grantAccess = function (action, resource) {
return async (req, res, next) => {
try {
const permission = roles.can(req.user.role)[action](resource);
if (!permission.granted) {
return res.status(401).json({
error: "You don't have enough permission to perform this action"
});
}
next();
} catch (error) {
next(error);
}
}
}
exports.allowIfLoggedin = async (req, res, next) => {
try {
const user = res.locals.loggedInUser;
if (!user)
return res.status(401).json({
error: "You need to be logged in to access this route"
});
req.user = user;
next();
} catch (error) {
next(error);
}
}
exports.signup = async (req, res, next) => {
try {
const { role, email, password } = req.body;
const hashedPassword = await hashPassword(password);
const newUser = new User({ email, password: hashedPassword, role: role || "basic" });
const accessToken = jwt.sign({ userId: newUser._id }, JWT_SECRET, {
expiresIn: "1d"
});
newUser.accessToken = accessToken;
await newUser.save();
res.json({
data: newUser,
message: "You have signed up successfully"
});
} catch (error) {
next(error);
}
}
exports.login = async (req, res, next) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user)
return next(new Error('Email does not exist'));
const validPassword = await validatePassword(password, user.password);
if (!validPassword)
return next(new Error('Password is not correct'));
const accessToken = jwt.sign({ userId: user._id }, JWT_SECRET, {
expiresIn: "1d"
});
await User.findByIdAndUpdate(user._id, { accessToken });
res.status(200).json({
data: { email: user.email, role: user.role },
accessToken
});
} catch (error) {
next(error);
}
}
exports.getUsers = async (req, res, next) => {
const users = await User.find({});
res.status(200).json({
data: users
});
}
exports.getUser = async (req, res, next) => {
try {
const userId = req.params.userId;
const user = await User.findById(userId);
if (!user)
return next(new Error('User does not exist'));
res.status(200).json({
data: user
});
} catch (error) {
next(error);
}
}
exports.updateUser = async (req, res, next) => {
try {
const { role } = req.body;
const userId = req.params.userId;
await User.findByIdAndUpdate(userId, { role });
const user = await User.findById(userId);
res.status(200).json({
data: user
});
} catch (error) {
next(error);
}
}
exports.deleteUser = async (req, res, next) => {
try {
const userId = req.params.userId;
await User.findByIdAndDelete(userId);
res.status(200).json({
data: null,
message: 'User has been deleted'
});
} catch (error) {
next(error);
}
}
My server.js -->
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const PORT = 4000;
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const playerRoutes = express.Router();
const userRoutes = express.Router();
const userController = require('./controllers/userController');
const user_routes = require('./apiroutes/route');
const app = express();
const JWT_SECRET = "$#GR24T4344$#$##%ETWWTEME%$6";
const users = "users";
require("dotenv").config({path: __dirname+ '../.env'});
let Player = require('./models/player.model');
let User = require('./models/user.model');
app.use(cors());
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: false
})
);
mongoose.connect('mongodb://127.0.0.1:27017/playerDB', function (err, db) {
if (err)
throw err;
db.createCollection(users, function (err, resp) {
if (err)
throw err;
console.log("Collection created!");
});
}, { useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function () {
console.log("MongoDB database connection established successfully");
});
..... blablablaaaa
app.use('/playerDB', playerRoutes);
app.use(async (req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
if (req.headers["x-access-token"]) {
try {
const accessToken = req.headers["x-access-token"];
const { userId, exp } = await jwt.verify(accessToken, JWT_SECRET);
// If token has expired
if (exp < Date.now().valueOf() / 1000) {
return res.status(401).json({
error: "JWT token has expired, please login to obtain a new one"
});
}
res.locals.loggedInUser = await User.findById(userId);
next();
} catch (error) {
next(error);
}
} else {
next();
}
});
app.use('/users', user_routes);
app.listen(PORT, function () {
console.log("Server is running on Port: " + PORT);
});
I hope you understand my approach and scenario? Can you guess, where it could have gone wrong? Any idea?
Missing npm packages or something more critical?
Look forward to some hints on this problem! Can't seem to figure out a way!
it seems you forgot to add this line to server.js
const jwt = require('jsonwebtoken');
While register and login, this didn't caused a problem, because for these requests, req.headers["x-access-token"] was null, and the code didn't reach the if block where you used jwt, but one a request with this header came (like getUsers) the code tried to use jwt.verify, but since jwt wasn't imported it gave error.