how do i edit this function of mine to get all users ? I have just started learning async await and i am having hard time learning how to get the request body.
here is my function :
export const get: Operation = async (
req: express.Request,
res: express.Response
) => {
commonUtility.showRequestParam(req);
let users: db.IUserDocument[] = [];
try {
// Describe data acquisition and registration from mongoDB here.
users = await UserModel.find()
.then(data => {
return data;
})
.catch(err => {
throw err;
});
} catch (err) {
// Error.
api.responseError(res, err);
}
if (users.length < 1) {
// this case is 404 ???
api.responseJSON(res, 200, []);
}
};
here is my user model:
export const usersSchema = new Schema({
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
BaseFields
});
export const UserModel = mongoose.model<db.IUserDocument>('Users', usersSchema);
You don't need to use .then when using async and await
export const get: Operation = async (
req: express.Request,
res: express.Response
) => {
commonUtility.showRequestParam(req);
let users: db.IUserDocument[] = [];
try {
users = await UserModel.find();
api.responseJSON(res, 200,users);
} catch (err) {
// Error.
api.responseError(res, err);
}
};
Read more about async await here -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Related
So I'm trying to fetch a row from my Postgres db table by id. In the function that calls the query there is data, but in the controller I'm getting a null. Seems like the controller is resolving before my query, but not sure why since I have await. My code is as follows:
TripQuery.ts
const Pool = require('pg').Pool
const pool = new Pool({
user: process.env.PG_USER,
host: process.env.PG_HOST,
database: process.env.PG_DATABASE,
password: process.env.PG_PASSWORD,
port: process.env.PG_PORT,
})
const dbGetTripById = async (id: string) => {
try {
await pool.query('SELECT * FROM trips WHERE id = $1', [id], (error: Error, results: QueryResult) => {
if (error) {
throw error
}
if (results.rows.length > 0) {
const trip: Trip = {
id: results.rows[0].id,
userId: results.rows[0].user_id,
name: results.rows[0].name,
}
console.log('from db:')
console.log(trip)
return trip
} else {
return null
}
})
} catch (e) {
console.log(e)
}
return null
}
TripController.ts
const getTrip = async (req: Request, res: Response) => {
const id = req.params.id
try {
const trip = await dbGetTripById(id)
console.log('from controller')
console.log(trip)
if (trip != null) {
res.status(200).json(trip)
} else {
res.status(404).send(`Trip with ID: ${id} does not exist`)
}
} catch (e) {
console.log(e)
}
}
TripRoutes.ts
import * as express from 'express'
import { addTrip, getTrips, getTrip, updateTrip } from '../controllers/TripController'
const router = express.Router()
router.get('/:id', getTrip)
export default router
When I call my endpoint http://localhost:3000/trips/123 I get the following logs:
Application is running on port 3000.
from controller
null
from db:
{ id: '123', userId: 'u123', name: 'trippy' }
And get the 404 error back even though the database query has fetched a value.
What am I doing wrong?
pool.query likely doesn't return a promise if a callback is passed.
Wrap it in a promise as:
const dbGetTripById = async (id: string) => {
return new Promise((resolve, reject) => {
pool.query('SELECT * FROM trips WHERE id = $1', [id], (error: Error, results: QueryResult) => {
if (error) {
return reject(error);
}
if (results.rows.length > 0) {
const trip: Trip = {
id: results.rows[0].id,
userId: results.rows[0].user_id,
name: results.rows[0].name,
}
console.log('from db:')
console.log(trip)
return resolve(trip)
} else {
return reject(new Error("Record not found"))
}
})
})
}
Or use promise syntax:
const dbGetTripById = async (id: string) => {
await pool.query('SELECT * FROM trips WHERE id = $1', [id])
.then(results => {
if (results.rows.length > 0) {
const trip: Trip = {
id: results.rows[0].id,
userId: results.rows[0].user_id,
name: results.rows[0].name,
}
console.log('from db:')
console.log(trip)
return trip
} else {
throw new Error("No results")
}
})
}
This is my server file.
In context I am not getting the request while my test is getting pass while test the required scenario.
export async function buildTestServer({
user,
headers,
roles,
}: {
user?: User;
headers?: { [key: string]: string };
roles?: Role;
}) {
const schema = await tq.buildSchema({
authChecker: AuthChecker,
validate: false,
resolvers: allResolvers(),
scalarsMap: [{ type: GraphQLScalarType, scalar: DateTimeResolver }],
});
const server = new ApolloServer({
schema,
context: async ({ req }) => {
const authHeader = headers?.authorization;
if (authHeader) {
const token = extractTokenFromAuthenticationHeader(authHeader);
try {
const user = await new UserPermissionsService(token).call();
return { req, user };
} catch {
return { req };
}
} else {
if (user) {
let capabilities: any = [];
if (roles) {
capabilities = roles.capabilities;
}
return {
req,
user: {
id: user.id,
customerId: user.customerId,
capabilities,
},
};
} else {
return { req };
}
}
},
});
return server;
}
And this is my test file from where I am sending the request to the server.
My test is getting passed but I am not getting the request headers. I want to check the the request. Can anybody help me out ?
const GET_LIST = `
query GetList($listId: String!) {
GetList(listId: $listId) {
id
}
}
`;
test('Get Lists', async () => {
const customer = await CustomerFactory.create();
const user = await UserFactory.create({ customerId: customer.id });
const list = await ListFactory.create({
customerId: customer.id,
});
const server = await buildTestServer({ user });
const result = await server.executeOperation({
query: GET_LIST,
variables: {
listId: list.id
},
});
var length = Object.keys(result.data?.GetList).length;
expect(length).toBeGreaterThan(0);
});
I have a route that is /mysafe/idofthemodel. When the idofthemodel isn't found it throws a cast error Cast to ObjectId failed for value "something" (type string) at path "_id" for model "modelname". Instead of the error I would like to have a 404 error.
Here is my route
app.get('/mysafe/:safeid',isLoggedIn,isAuthor, async(req,res)=> {
const { safeid } = req.params;
const safe=await Safe.findById(safeid).populate('author')
const password = await Password.find({safe:safeid}).populate('safe')
res.render('passwords/index', { password,safe })
})
Schemas:
const PasswordsSchema = new Schema({
title: String,
url: String,
password: String,
safe: {
type: Schema.Types.ObjectId,
ref: "Safe"
},
})
const SafeSchema = new Schema({
author: {
type: Schema.Types.ObjectId,
ref: "User"
},
})
Here I'm using EJS to render the 404 Error page,
and the page file is located in views/errors/404.ejs
const { safeid } = req.params;
try {
const safe = await Safe.findOne({ _id: mongoose.Types.ObjectId(safeid) }).populate('author')
if (!safe) {
return res.status(404).render('errors/404.ejs')
}
const password = await Password.findOne({ safe: mongoose.Types.ObjectId(safeid) }).populate('safe')
return res.render('passwords/index', { password, safe })
}
catch (error) {
return res.status(500).render('errors/500')
}
middleware.js
module.exports.isAuthor = (req, res, next) => {
const { safeid } = req.params
if (!mongoose.Types.ObjectId.isValid(safeid)) {
return res.status(404).render('errors/404.ejs')
}
Safe.findById(safeid).then(safe => {
if (!safe) {
return res.status(404).render('errors/404.ejs')
}
if (!safe.author._id.equals(req.user._id)) {
req.flash('error', 'Notfound');
return res.redirect('/');
}
next();
});
}
it seems that the create method does not return any promise that then can handle
I tried different things but nothing worked
this is my routes file
const express = require("express")
const router = express.Router();
const controller = require("./controller")
router.post("/signup", controller.create);
module.exports = router;
and this is my model file
const mongoose = require('mongoose');
const User = new mongoose.Schema(
{
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
picture: {
type: String
},
password: {
type: String,
select: false
},
email: {
required: true,
type: String,
unique: true
}
},
{
timestamps: true
}
);
User.index({
firstName: 'text',
lastName: 'text',
});
module.exports = mongoose.model('User', User);
and this is the controller file
const User = require('./model');
const { hash, compareHash } = require('../lib/util');
const { createToken, findUserByToken } = require('../lib/auth');
const cookieIsSecure = process.env.ENVIRONMENT === 'production';
exports.create = async (req, res) => {
const password = await hash(req.body.password);
const rawUser = {
...req.body,
password,
};
User.create(rawUser)
.then(async user => {
return user.save();
})
.then(async user => {
const newUser = user.toObject();
res.send(newUser);
})
.catch(err => {
if (err.code === 11000) {
res.status(400).send({ message: 'A user with this email address has already registered.' });
return;
}
res.status(500).send({ message: 'An unexpected error occurred' });
});
};
it always return the 500 error "an unexpected error occurred"
which is not really specific. and i do not know what is the problem exactly. but I am sure it has something to do with the model.create() it does not return any promise.
Here you are mixing methods. create doesn't want save in it as it's implicit:
https://mongoosejs.com/docs/api.html#model_Model.create
Please try this, I've refactored your code a bit and added much easier to read and use try/catch:
const rawUser = new User({ ...req.body, password});
try {
await rawUser.save();
res.status(201).send(newUser);
} catch(err) {
if (err.code === 11000) return res.status(400).send({ message: 'A user with this email address has already registered.' });
res.status(500).send({ message: 'An unexpected error occurred' });
}
You need to use async/await like this:
exports.create = async (req, res) => {
try {
const password = await hash(req.body.password);
const rawUser = {
...req.body,
password
};
const user = await User.create(rawUser);
const newUser = user.toObject();
res.send(newUser);
} catch (err) {
console.log("ERROR: ", err);
if (err.code === 11000) {
return res.status(400).send({
message: "A user with this email address has already registered."
});
}
res.status(500).send({ message: "An unexpected error occurred" });
}
};
I used this method because I am storing an array of classified messages, I would like to vividly understand why it doesn't update.
Here's the db.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ObjectId = mongoose.Types.ObjectId;
const usersessionSchema = new Schema({
fb_id: String,
fb_name: String,
fb_profpic: String,
message_body: [
{
message: String,
message_type: String,
timestamp: String
}
],
admin: Boolean,
branch: String
});
const model = (prefix) => {
prefix = prefix || '';
console.log(prefix);
if (prefix.length > 0) {
return mongoose.model(prefix + "-usersessions", usersessionSchema);
} else {
return new Error('Undefined collection prefix!');
}
}
/** Push message into message body*/
module.exports.pushsession =
async(model, id, data) => {
return new Promise((resolve, reject) => {
console.log(data);
model.findOneAndUpdate({fb_id: id}, {$push: {data}},{safe: true})
.then(res => {
console.log(res);
/
resolve(res);
})
.catch(err => {
reject(err);
console.log(err);
throw err;
});
});
}
Here's the controller.js:
/** Push usersession message */
module.exports.pushsession =
async(req, res, next) => {
try {
//jwt.validateToken(req);
var en = "en";
var dateEn = moment().locale(en);
format = "MM/DD/YYYY h:mm:ss A"; //h:mm:ss.SSS if you want miliseconds
var datetime_now = dateEn.format(format);
console.log(datetime_now);
var request = {
message_body: {
message: req.body.message,
message_type: req.body.message_type,
timestamp: datetime_now
}
};
const model = usersessionDB(req.query['client']);
const id = req.body.fb_id;
const result = await usersessionDB.pushsession(model, id, request);
if (result) {
response.success(res, next, result, 200, response.HTTP_STATUS_CODES.ok);
} else {
response.failure(res, next, {
message: 'ID does not exist'
}, 404, response.HTTP_STATUS_CODES.not_found);
}
} catch (err) {
response.failure(res, next, err, 500, response.HTTP_STATUS_CODES.internal_server_error);
}
}
Here's the route.js:
const controller = require('../controller/usersession-controller');
module.exports =
(server) => {
server.post('/api/session', controller.create);
server.get('/api/session', controller.list);
server.get('/api/session/:id', controller.get);
server.put('/api/session/:id', controller.update);
server.del('/api/session/:id', controller.delete);
server.put('/api/pushsession', controller.pushsession);
}
Visually, if you run this using postman, you can see that it display the one I want to search and update
Result of the postman
What I want to happen is to insert another set of array inside that message_body
Data I've inserting
My desired output
This code is working without that promise something, but in my project it is needed so I can't remove that thing.
So, based on :
This code is working without that promise something
i can point a thing or two,
in db.js
module.exports.pushsession =
async(model, id, data) => {
return new Promise((resolve, reject) => {
you don't need async since you're returning a promise so replace this
async(model, id, data) => {
with
(model, id, data) => {
and since you're returning a promise and removed async , you don't need the await on the other side ( controller.js ), so this
const result = await usersessionDB.pushsession(model, id, request);
if (result) {
response.success(res, next, result, 200, response.HTTP_STATUS_CODES.ok);
} else {
should be
usersessionDB.pushsession(model, id, request).then(
(result) => { // when resolved
response.success(res, next, result, 200, response.HTTP_STATUS_CODES.ok);
},
(err) => { // when rejected
response.failure(res, next, {
message: 'ID does not exist'
}, 404, response.HTTP_STATUS_CODES.not_found);
});
this is a comparison between async/await and promises : Javascript Promises vs Async Await. Difference?
and here's some good examples of using promises : https://medium.com/dev-bits/writing-neat-asynchronous-node-js-code-with-promises-32ed3a4fd098
i think your $push is ok but you already said
This code is working without that promise something
i hope this helps and Good luck :)
I tried cleaning my code
here's the controller.js:
/** Push usersession message */
module.exports.pushsession =
async (req, res, next) => {
try {
//jwt.validateToken(req);
var en = "en";
var dateEn = moment().locale(en);
format = "MM/DD/YYYY h:mm:ss A"; //h:mm:ss.SSS if you want miliseconds
var datetime_now = dateEn.format(format);
console.log(datetime_now);
var data = {
message: req.body.message,
message_type: req.body.message_type,
timestamp: datetime_now
};
const model = usersessionDB(req.query['client']);
const id = req.body.fb_id;
console.log(id);
const result = await usersessionDB.pushsession(model, id, data).then(
(result) => { // when resolved
response.success(res, next, result, 200, response.HTTP_STATUS_CODES.ok);
},
(err) => { // when rejected
response.failure(res, next, {
message: 'ID does not exist'
}, 404, response.HTTP_STATUS_CODES.not_found);
});
} catch (err) {
response.failure(res, next, err, 500, response.HTTP_STATUS_CODES.internal_server_error);
}
}
Here's the db.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ObjectId = mongoose.Types.ObjectId;
const usersessionSchema = new Schema({
fb_id: String,
fb_name: String,
fb_profpic: String,
message_body:[{
message: String,
message_type: String,
timestamp: String
}],
admin: Boolean,
branch: String
});
/** Push message into message body*/
module.exports.pushsession =
async(model, id, data) => {
console.log(data);
return new Promise((resolve, reject) => {
model.findOneAndUpdate({fb_id: id}, { $push: { message_body: data }})
.then(res => {
console.log(res);
resolve(res);
})
.catch(err => {
reject(err);
console.log(err);
throw err;
});
});
}
Out of the blue after I tried to replace $push with $set then again I replace it with $push, it worked.
I don't if there's a difference, or I miss something, feel free to point it out.