routing express node js - javascript

I have the following routes methods in my controller:
getListaUsuarios() {
this.app.get("/api/usuario", (req, res) => {
this.usuario.getListaUsuarios().then((results) => {
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
});
}
getUsuarioByEmail() {
this.app.get("/api/usuario/:usuarioEmail", (req, res) => {
let usuarioEmail = req.params.usuarioEmail;
this.usuario.getUsuarioByEmail(usuarioEmail).then((results) => {
if(!results) return res.status(404).json();
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
});
}
My question is related with the routes, for best practices we know that we should be using the name of the resources, in the first method I'm retrieving the list of Users and in the second I'm trying to retrieve the user by email. But when I try to call the api with: localhost:3000/api/usuario?usuarioEmail=xxxx#xxx.com it always call the first method and not the second. Is there something wrong with the way I'm defining my routes, or I have to change the complete path always.

In the url localhost:3000/api/usuario?usuarioEmail=xxxx#xxx.com, usuarioEmail is a query string; your rout is expecting it as a parameter. The correct usage given your routes would be:
localhost:3000/api/usuario/xxxx%40xxx.com
Where %40 represents the URI encoding of #.
If you actually wanted to use query strings, you would need to do something like this:
getListaUsuarios() {
this.app.get("/api/usuario", (req, res) => {
if (!req.query.usarioEmail) { // check for the query string
let usuarioEmail = req.params.usuarioEmail;
this.usuario.getUsuarioByEmail(usuarioEmail).then((results) => {
if(!results) return res.status(404).json();
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
} else {
this.usuario.getListaUsuarios().then((results) => {
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
}
});
}

Apparently you are mixing req.params with req.query
req.query
Works when you want to use an url just like the one you posted
localhost:3000/api/usuario?usuarioEmail=xxxx%40xxx.com
and the logic has to be setup in the /api/usuarios route
getListaUsuarios() {
this.app.get("/api/usuario", (req, res) => {
if (req.query.usuarioEmail) { //Aply your logic over here
/*If wont change the value of usuarioEmail, you should use
const instead of let*/
const usuarioEmail = req.params.usuarioEmail;
return this.usuario.getUsuarioByEmail(usuarioEmail).then((results) => {
if(!results) return res.status(404).json();
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
}
this.usuario.getListaUsuarios().then((results) => {
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
});
}
req.params
Is used when you want to do something like this
localhost:3000/api/usuario/micorreo%40email.com
And your route will look exactly like you have defined it
/api/usuario/:usuarioEmail
The value of :usuarioEmail is in req.params.usuarioEmail
If you want to know more about the req object, here's a link to the Express documentation

Related

router.delete returns empty array

I'm trying to add a function that deletes a record in MongoDB by the id, but I'm getting an empty array as a result and the record is not deleted.
Here is my code so far:
//router
router.delete('/comandas/:id', (req, res) => {
deleteLine(req.params.id)
res.status(500).end()
});
});
//delete function
const objectId = require('mongodb').ObjectID;
const init = () =>
MongoClient.connect(connectionUrl, { useNewUrlParser: true, useUnifiedTopology: true }).then((client) => {
db = client.db(dbName)
})
const deleteLine = (id) => {
const collection = db.collection('comanda')
return collection.deleteOne({"_id": objectId(id)})
}
You are returning a promise in deleteLine function, in your router to actually make it run you need to add then block like this:
deleteLine(req.params.id).then(result => {
console.log(result);
//todo: send response
})
.catch(err => {
console.log(err);
//todo: send error response
})
I found another way to solve this calling the get methods instead:
router.get('/comandas/:id/delete', (req, res) => {
deleteLine(req.params.id)
.then( () => {
console.log(req.params.id + ' deleted')
res.status(500).end()
})
.catch((err) => {
console.log(err)
res.status(500).end()
});
});

Async Wait Issue with Service when called out from the Controller in Nodejs

I am currently trying to do a get request in my NodeJS API, get some data and return the modified value.
From what I read in other similar questions is that you cannot just return the modified object but you need to use a callback function or a promise in order to return it. I have a standard MVC pattern where I use a controller, service.
Here is my service:
const rp = require('request-promise');
exports.RequestUserPermissions = async function(role, next) {
try {
await rp('https://api.myjson.com/bins/7jau8').then(response => {
const permissionsResponse = JSON.parse(response);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
console.log(filteredPermissions); // I GET UNDEFINED HERE.
return filteredPermissions;
});
} catch (error) {
console.log(error);
next(error);
}
};
Here is my controller:
const UserPermissionsService = require('../services/userPermissions.service');
exports.getUserPermissions = async function(req, res) {
try {
const role = req.headers.role; // console.log(req.headers.role);
const loggedInUserPermissions = await UserPermissionsService.RequestUserPermissions(role);
return res.status(200).json({ status: 200, data: loggedInUserPermissions, message: 'User permissions retrieved.' });
} catch (error) {
throw Error(error, 'error inside the get.user.permissions function');
}
};
So my issue is that I'm trying to return the value of filteredPermissions to my controller but I keep getting undefined. Which I guess it's a async - await issue. Meaning that the function ends before I make my calculations.
I originally had my service as:
await request.get('https://api.myjson.com/bins/7jau8', (error, response, body) => {
if (!error && response.statusCode === 200) {
const permissionsResponse = JSON.parse(body);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
return permissionsResponse;
} else {
console.log('Got an error:', error);
}
});
but I changed it to use the request-promise module, so that I can return my response. What am I doing wrong ? How can I pass my calculations properly??
Change this:
await rp('https://api.myjson.com/bins/7jau8')
to this:
return rp('https://api.myjson.com/bins/7jau8')
You need to be returning something useful from your exports.RequestUserPermissions function. As it stands now, there's no return value from that function which means the promise it returns will just have an undefined resolved value which is apparently what you are experiencing.
Then, I'd suggest using a .catch() for the error condition. And, you need to allow the caller to see the error (probably as a rejected promise) so it can know when there's an error.
I would suggest this:
const rp = require('request-promise');
exports.RequestUserPermissions = function(role, next) {
return rp('https://api.myjson.com/bins/7jau8').then(response => {
const permissionsResponse = JSON.parse(response);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
console.log(filteredPermissions); // I GET UNDEFINED HERE.
return filteredPermissions;
}).catch(error => {
console.log(error);
next(error);
throw error;
});
};
The spec for exactly what you want is a bit confused. To be able to test things with the URL you gave me, I created a simple stand-alone node program here. This looks for one matching role and returns that. If no matching role is found, it resolves to null. You could also make that reject, depending upon how the caller wants no matching role to work.
const rp = require('request-promise');
function getRole(role) {
return rp({uri: "https://api.myjson.com/bins/7jau8", json: true}).then(data => {
// need to find the matching role
// apparently role can be a string or an array of strings
for (let item of data) {
if (item[role]) {
return item[role];
}
}
return null;
});
}
getRole("admin").then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
When, I run this, I get this output:
{ static:
[ 'posts:list',
'posts:create',
'posts:edit',
'posts:delete',
'users:get',
'users:getSelf',
'home-page:visit',
'dashboard-page:visit' ]
}
Hopefully, can you take this an modify to fit your other needs.
Note: I'm using the json:true option with rp() so it will parse the JSON response for me automatically.
If you are using async/await with request-promise then you don't need to call .then(), you can just assign your rp call directly to a variable. For example this:
await rp('https://api.myjson.com/bins/7jau8').then(response => {
const permissionsResponse = JSON.parse(response);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
console.log(filteredPermissions); // I GET UNDEFINED HERE.
return filteredPermissions;
});
Would become this:
const response = await rp('https://api.myjson.com/bins/7jau8');
const permissionsResponse = JSON.parse(response);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
console.log(filteredPermissions); // I GET UNDEFINED HERE.
return filteredPermissions;

How to return a promise from a boolean check inline?

I'm new to promise syntax. Previously I had code like this, and requests would return a zipfile:
// in first file
exports.requireSubscription = function(req) {
if (feature_is_available) {
return Promise.resolve();
}
else {
return Promise.reject(new Error("You need to upgrade your account to access this feature."));
}
};
//from the npm package https://www.npmjs.com/package/archiver
const archiver = require("archiver");
utils.requireSubscription(req)
.then(() => getPage(req, res, "view"))
.then(function(page) {
const zip = archiver.create("zip", {});
// ...
zip.finalize();
}).catch(utils.fail(req, res));
Now I want to remove the separate function for requireSubscription, and use a single file with a check inline.
I've tried this:
if (feature_is_available) {
getPage(req, res, "view"))
.then(function(page) {
const zip = archiver.create("zip", {});
// ...
zip.finalize();
});
} else {
utils.fail(req, res);
}
However, the request is hanging. I think perhaps I'm not returning a promise when I should be returning one - previously requireSubscription returned a promise, now my inline check does not.
How can I rewrite this to return the right thing?
Update: here is the utils.fail function:
exports.fail = function(req, res) {
return function(error) {
if (error instanceof acl.PermissionDeniedError) {
return res.status(403).render("error_nothing_here.html", { user: req.user, error: error });
}
else if (error instanceof errors.NotFoundError) {
return res.status(404).render("error_nothing_here.html", { user: req.user, error: error });
}
res.status(500).render("internal_error.html", { "error": error });
};
};
You can use a ternary operator to inline the body of the function as a single expression:
(feature_is_available
? Promise.resolve()
: Promise.reject(new Error("You need to upgrade your account to access this feature."))
).then(() =>
getPage(req, res, "view")
).then(page => {
const zip = archiver.create("zip", {});
// ...
zip.finalize();
}).catch(utils.fail(req, res));
The problem with your version that the promise chain had no catch handler attached, and that you didn't call the function that was created by fail() in the else branch. You would need to write
if (feature_is_available) {
getPage(req, res, "view"))
.then(page => {
const zip = archiver.create("zip", {});
// ...
zip.finalize();
})
.catch(utils.fail(req, res));
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
} else {
utils.fail(req, res)(new Error("You need to upgrade your account to access this feature."));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

Function that calls function containing async query to mongodb.find [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
Is there a way to call function that contains mongoose query inside other function, so other function will work properly?
My first function containing mongoose query:
getUserTags = (id) => {
User.findById(id)
.exec( (error, user) => {
if (error) {
return next(error);
} else {
return user;
}
})
}
and my functions that needs to call that first function:
userTagToBookTagValues = (id) => {
const user = getUserTags(id);
//I NEED THIS PART TO WORK AFTER getting data from getUserTags
console.log(user);
user.tags.forEach(tag => {
console.log(tag)
});
}
Is there a way so it works properly and user in second function will not be undefined?
You maybe need to return User.findById?
Like so:
getUserTags = (id) => {
return User.findById(id)
.exec( (error, user) => {
if (error) {
return next(error);
} else {
return user;
}
})
}
As I understand .exec() do not return anything, so using .then gives error.
However if rewritten like this, it works perfectly:
getUserTags = (id) => {
return User.findById(id)
}
userTagToBookTagValues = (id) => {
const user = getUserTags(id).then((user) => {
user.tags.forEach(tag => {
console.log(tag)
});
}) ;
}
findById is an asynchronous method.
If your node version greater then 8
getUserTags = id => User.findById(id).exec();
userTagToBookTagValues = async (id) => {
try {
const user = await getUserTags(id);
user.tags.forEach(tag => {
console.log(tag)
});
} catch (err) {
next(err);
}
}
Or you can use then method after calling getUserTags function.
For more information about of asnc methods:
Medium

Please break down the event path of a Callback Function into an ORM file

I was tasked with creating a small application using Object Relational Mapping (ORM) for class. It's a fairly simple application, that takes client side input, places it into the database and also displays it back to the client.
However, I am having a hard time understanding the breakdown in what is happening as we pass code between 3 files. There is a burgers-controller.js file which requires a burgers.js file which requires the orm.js file. For anyone who wants to see the full code you can find it on my Github.
I get the reasoning and benefits of using an ORM and modularizing everything but I need someone to break down what is happening inside the code and in what order.
So in burgers-controller.js file we have the following code.
router.get("/", (req, res)=>{
burgers.selectAll((result)=>{
let handlebarsObj = {
burgers: result
}
res.render("index", handlebarsObj)
});
})
Then inside burgers.js we have the following code.
let burgers = {
selectAll: (callback)=>{
orm.selectAll("burgers", (result)=>{
callback(result);
})
}
}
And finally in orm.js we have.
let orm = {
selectAll: (tableName, callback)=>{
let queryString = "SELECT * FROM ??"
connection.query(queryString, tableName, (err, data)=>{
if (err){console.error("ERROR: " + err.stack)}
callback(data)
})
}
}
The ORM file is connected to a MySQL database.
Would you explain what is happening here, and in what order?
I think I got it, although its a shot in the dark since there are no indication of what the actual error is, in your description. Please forgive me if I mistakes.
The callback from burgers-controller.js which is sent to burgers.selectAll( is executed inside burgers.js. When its executed inside burgers.js and not within burgers-controller.js it wont have access to res object, which is only present in burgers-controller.js.
We can solve the problem using promises. I am going to use native one here, but you are free to use any other package (eg: bluebird):
// burgers-controller.js
router.get('/', (req, res)=> {
burgers
.selectAll()
.then((result) => {
let handlebarsObj = {
burgers: result
}
res.render('index', handlebarsObj)
})
})
// burgers.js
let burgers = {
selectAll: () => {
return new Promise((resolve, reject) => {
orm.selectAll('burgers', (result) => {
resolve(result)
})
})
}
}
You can use promises everywhere are deal with failures more gracefully:
// burgers-controller.js
router.get('/', (req, res)=> {
burgers
.selectAll()
.then((result) => {
let handlebarsObj = {
burgers: result
}
res.render('index', handlebarsObj)
})
.catch((err) => {
let errMsg = {
message: err.message,
error: err
}
res.render('index', errMsg)
})
})
// burgers.js
let burgers = {
selectAll: () => {
return new Promise((resolve, reject) => {
orm
.selectAll('burgers')
.then((result) => {
resolve(result)
})
.catch((err) => {
reject(err)
})
})
}
}
// orm.js
let orm = {
selectAll: (tableName) => {
return new Promise((resolve, reject) => {
let queryString = "SELECT * FROM ??"
connection.query(queryString, tableName, (err, data)=>{
if (err) {
console.error("ERROR: " + err.stack)
reject(err)
} else {
resolve(data)
}
})
})
}
}

Categories