I had this route and it worked perfectly
router.get('/api/User/:id',async(req,res)=>{
try {
const{id}=req.params;
let result =await pool1.request()
.input('Iduser', sql.Int, id)
.execute('GetUser')
res.json(result);
}
catch (err) {
res.json({ error: 'Does Not exist' })
}
});
But I want to separate the function and leave the route as clean as possible, try to separate it as follows but I get the following error: TypeError: one is not a function
Route
router.get('/api/User/:id', async(req,res)=>{
try {
res.json((await one(req.params.id))[0]);
} catch (err) {
console.log(err);
res.sendStatus(500);
}
})
Function
const one = async(id)=>{
return new Promise((resolve,reject)=>{
pool.request()
.input('Iduser', sql.Int, id)
.execute('User')((err,results) =>{
if(err){
return reject(err);
}
resolve(results);
});
});
}
What is my mistake, am I calling the function wrong?
to make your code cleaner you can do this :
const getUserById =async(req,res)=>{
try {
const{id}=req.params;
let result =await pool1.request()
.input('Iduser', sql.Int, id)
.execute('GetUser')
res.json(result);
}
catch (err) {
res.json({ error: 'Does Not exist' })
}
}
router.get('/api/User/:id',getUserById);
also to make it cleaner more you can do it like this
export const asyncHandler = (fn) => async (request, response, next) => {
try {
return await fn(request, response, next);
} catch (error) {
return next(error); // or response.json({ error: 'Does Not exist' })
}
};
const getUserById =async(req,res)=>{
const { params: { id } }=req;
const result =await pool1.request()
.input('Iduser', sql.Int, id).execute('GetUser');
return res.json(result);
}
router.get('/api/User/:id',asyncHandler(getUserById));
Thanks mate, I solved why he tells me that it was not a function, I was not calling it well but the way you explain it the route is much cleaner
function
const one = async(id)=>{
return new Promise((resolve,reject)=>{
pool.request()
.input('IdUser', sql.Int, id)
.execute('GetUser',(err,results)=>{
if(err){
return reject(err);
}
resolve(results);
}
)
});
}
route
router.get('api/user/:id', async(req,res)=>{
try {
let result=await m.one(req.params.id);
res.json(result);
} catch (error) {
console.log(error);
res.sendStatus(500);
}
})
Related
How can I get a full data except deleted, after delete?
Project.findOneAndRemove({_id: projectID, name: projectName},
function(err, project){
if (err) {
return res.json({message: 'Error on the server!', status: 500 });
}
// Here I need a full data except deleted one
console.log(project)
return res.json({project, status:200});
}
)
or Do I find again inside success callback to get full data?
Project.find({}, function(err, projects){
if (err) return res.json({message: 'Error on the server!', status: 500 });
return res.json(projects);
});
This might help you.
router.post('/deleteAndReturn', async (req, res) => {
try {
await Project.findOneAndRemove({ _id: projectId })
const projects = await Project.find({})
return res.status(200).json(projects)
} catch (err) {
res.status(500).send("Server Error")
}
})
I am trying to write some code and it work but i ran into a problem where bcrypt makes use of callback and i am trying to resolve it with promise. Here is the code:
`UserSchema.statics.findByData = function(username,password) {
var User = this;
User.findOne({username}).then((user) => {
if(!user){
return Promise.reject();
}
return new Promise((resolve,reject) => {
bcrypt.compare(password,user.password,(err,res) => {
if(res){
resolve(user);
}else {
reject();
}
});
});
});
};`
I call this function from here :
User.findByData(body.username,body.password).then((user) => {
res.send(user);
}).catch((e) => {
res.status(400).send();
});
I get an error: `Cannot read property 'then ' of undefined.
Why i am getting this error?
As stated in the first comment you need to return User.findOne which will be promise. So no need to create another promise. whenever you will return, then will be called with the returned value. You can use Promise.reject() and Promise.resolve() to call catch and then respectively as well.
UserSchema.statics.findByData = function(username,password) {
var User = this;
return User.findOne({username}).then((user) => {
if(!user){
Promise.reject('No user found');
}
bcrypt.compare(password,user.password,(err,res) => {
if(res){
Promise.resolve(user);
}else {
Promise.reject(err);
}
});
});
};
i need to know how i can write my request to make multiple delete.
the second thing is how can i put async function on my code.
i want to delete a campus and in the same time dele the builings with the same id campus in the JSON
app.delete('/campuses/:id', (req, res)=> {
const id = req.params.id;
const details = { 'campusid': new ObjectID(id) };
db.db('').collection('buildings').remove(details, (err, result)=> {
if (err) {
res.send({ 'error': 'en error has occured' });
} else {
res.send(result);
}
});
const details2 = { '_id': new ObjectID(id) };
db.db('').collection('campuses').remove(details2, (err, result)=> {
if (err) {
res.send({ 'error': 'en error has occured' });
} else {
res.send(result);
}
}
);
})
You can delete like this.
app.delete('/campuses/:id', async (req, res)=> {
try {
const id = req.params.id;
const details = { 'campusid': new ObjectID(id) };
await db.db('').collection('buildings').remove(details);
const details2 = { '_id': new ObjectID(id) };
await db.db('').collection('campuses').remove();
res.send(result);
} catch(err) {
return res.json({
success: false,
message: 'error'
});
}
})
You could make sequential functions where the first one calls the second one. You could then pass on variables to the seconds function (ie. your campus ID).
It could look something like this:
const Query1 = (res, query) => {
const request = new sql.Request();
request.query(query, (err, result) => {
if (err) {
return res.json({
success: false,
message: 'error'
});
} else if (result.recordset[0]) {
let campusID = result.recordset;
Query2(res, campusID, query = 'SELECT bla bla')
}
})
}
const Query2 = (res, campusID, query) => {
const request = new sql.Request();
request.query(query, (err, result) => {
if (err) {
return res.json({
success: false,
message: 'error'
});
} else {
return res.json({
success: true
});
}
})
}
There are various ways to make async call.
You can use promises.
Async Functions.
Sending response without waiting for other tasks.
If you want to make parallel calls you can use bluebird join function
I like the syntax of async functions better than promises, but I use both depending on the situation.
Here is an example of running functions in order before moving to the next function:
async.waterfall([
function(callback1) {
//Do some work, then callback
if (error) {
callback1(errorGoesHere,null);
} else {
callback1(null,successMessageGoesHere);
}
},
function(callback2) {
//Do some work, then callback
if (error) {
callback2(errorGoesHere,null);
} else {
callback2(null,successMessageGoesHere);
}
}
], function (error, success) {
if (error) {
//show an error
}
//all good return the response, etc.
});
If anything in these functions fail, it automatically call the end function to catch the error.
I have some problem with promise functions, my app has this structure:
- routes
- service
- db
db is a class initialized when the application start and where I created some wrapper function for insert/find/ecc..., service is a layer between the route and db, here I do most of the work. My problem is that with the code below if a user already exist I want to throw an error or reject the promise but when I try to do something like this I get
Cannot read property 'then' of undefined
where is the error?
This is my resource:
router.put('/', (req, res, next) => {
bcrypt.hash(req.body.password, 10)
.then(function (hash) {
req.body.password = hash;
service.addUser(req.body)
.then((user) => {
return res.json(user);
})
.catch((err) => {
return res.json(err);
});
})
.catch((err) => {
return res.json(err);
});
});
This is the service:
getBy(query) {
return this.mongo.find(query);
}
addUser(data) {
if(!data.email) {
return Promise.reject('email_missing');
}
const self = this;
self.getBy({ email: data.email })
.then((user) => {
if(user.length) {
return Promise.reject('user_exist');
}
return self.mongo.insert(data)
})
.catch((err) => {
return Promise.reject(err);
});
}
and this is the db connection:
find(query) {
const self = this;
return new Promise((resolve, reject) => {
self.collection.find(query).toArray((err, res) => {
if (err) {
self.logger.info('Mongo::find error', err);
reject(err);
} else {
self.logger.info('Mongo::find', query);
resolve(res);
}
});
});
}
insert(data) {
const self = this;
return new Promise((resolve, reject) => {
self.collection.insert(data, (err, res) => {
if (err) {
self.logger.info('Mongo::insert error', err);
reject (err)
} else {
self.logger.info('Mongo::insert', res);
resolve(res)
}
});
});
}
many thanks!
The addUser function does not return a Promise. The code should look like this:
addUser(data) {
if (!data.email) {
return Promise.reject('email_missing');
}
const self = this;
return self.getBy({
email: data.email
})
.then((user) => {
if (user.length) {
return Promise.reject('user_exist');
}
return self.mongo.insert(data)
})
.catch((err) => {
return Promise.reject(err);
});
}
The .catch block here does not make sense because it just contains return Promise.reject(err) so you can remove it:
addUser(data) {
if (!data.email) {
return Promise.reject('email_missing');
}
const self = this;
return self.getBy({
email: data.email
})
.then((user) => {
if (user.length) {
return Promise.reject('user_exist');
}
return self.mongo.insert(data)
});
}
In the router you also have to return the Promise in the .then and you can remove one .catch block:
router.put('/', (req, res, next) => {
bcrypt.hash(req.body.password, 10)
.then(function(hash) {
req.body.password = hash;
return service.addUser(req.body) // return the Promise ehre
})
// the then can be move out here, to avoid nesting
.then((user) => {
return res.json(user);
})
// only on catch is required
.catch((err) => {
return res.json(err);
});
});
An additional note, you should always reject with a real error. So it would be better to write, Promise.reject(new Error('user_exist'))
Nesting promises is an anti-pattern.
See item #2 in Promise Patterns & Anti-Patterns
It's considered an anti-pattern because it reduces understandability and overly complicates the call stack making debugging (more of) a nightmare.
So rather than:
bcrypt.hash(req.body.password, 10)
.then(function (hash) {
req.body.password = hash;
service.addUser(req.body) // ANTI-PATTERN
.then((user) => {
return res.json(user); // [1]
})
.catch((err) => {
return res.json(err); // [2]
});
})
.catch((err) => {
return res.json(err);
});
});
Do this instead:
const SALT_ROUNDS = 10
app.get(URL, function(req, res) {
function setHashedPassword() {
// TODO first test for existence of password in req.body
return bcrypt.hash(req.body.password, SALT_ROUNDS)
.then(hash => req.body.password = hash)
}
function addUser() {
return service.addUser(req.body)
}
Promise.all([ setHashedPassword(), addUser() ])
.then((results) => {
const user = results[1]
res.json(user)
})
.catch((err) => {
res.json(err)
})
})
Note that, at [1] and [2] in the OP's code, it makes no sense to return anything since there is no active context to which you can return a value.
I'd also respond with an object like:
res.json({ok:true, user:user})
and
res.json({ok:false, error:err})
So you can check for success or failure in the client.
Yes, I know you might believe that ok is redundant here, but it's good practice to standardize on a single result value so you don't have to first test for the existence of error before you check for the existence of user.
There's no respone for below save method. I wonder why.
app.post('/something', function (req, res) {
mainModel.save(req.body.data ,function(err,data){
if(err){
console.log(err)
}else{
console.log(data)
}
});
});
Here's how my models/main.js look like http://pastebin.com/eQSFXWb5
You didn't return any response after save. you should return response ie. return res.status(400).send().
you can try it
app.post('/something', function (req, res) {
if(!req.body.data) {
return res.status(400).send({masg: 'Invalid data'});
}
var newMainModel = new mainModel(req.body.data);
newMainModel.save(function(err,data){
if(err){
console.log(err)
return res.status(400).send({masg: 'Error occurred'});
}
console.log(data);
return res.status(200).send(data);
});
});