Having multiple get routes on a NodeJS / Express REST API? - mysql

I'm creating a JS web app using NodeJS and Express (with SQL/MySQL for the database), pretty much directly implementing this API tutorial: https://www.bezkoder.com/node-js-rest-api-express-mysql/ (just replacing 'tutorials' with 'Employees').
I'm trying to write API functions to get all Employees with certain attributes (in the SQL table), for example all employees with lastName = "Garcia" or all employees with teamID = 43682, etc.
In my routes.js file I have this:
module.exports = app => {
const employees = require("../controllers/employee.controller.js");
const router = require("express").Router();
// Create a new Employee
router.post("/", employees.create);
// Retrieve all Employees
router.get("/", employees.findAll);
// Retrieve all Employees with lastName
router.get('/', employees.findLastName);
... a bunch more CRUD functions ...
app.use('/api/employees', router);
};
And this is the corresponding Controller function:
exports.findLastName = (req, res) => {
const lastName = req.query.lastName; // tried changing req.query.lastName to req.params.lastName
Employee.getLastName(lastName, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Error occurred while retrieving by last name."
});
else {
console.log(`Employees with lastName ${lastName} were found!` );
res.send(data);
}
});
};
exports.findAll = (req, res) => {
const title = req.query.title;
Employee.getAll(title, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving employees."
});
else {
console.log(`Employee with ${title} title was found!` );
res.send(data);
}
});
};
The findAll route/function (just copied from that tutorial) works by finding all Employees with a certain ID number (the primary key in the DB) and I know that works from testing it through Postman. I wrote the findLastName route/function by copying the findAll function and changing it to search by lastName, and making the corresponding functions in the model and controller classes.
The new function, findLastName, doesn't work... unless I put the route before the findAll route (or comment it out). Then it correctly calls all my functions and returns all employees with the lastName param.
What's actually happening here? Are you not allowed to have multiple .get() routes or something? If so, how would I implement a search API like this? This is my first time building a web app like this so admittedly I'm still a little hazy on how routing and all that works. Thank you for any help though!

In Express whenever the first route matches second will be ignored, so in your scenario you have two route.get with same path /
router.get('/', employees.findAll);
//Since route with path `/` is matched above already this will be ignored
router.get('/', properties.findLastName);
In order to find Employees with last name you will need to create a new route with param (param will contain the last name)
router.get('/:lastName', properties.findLastName);
You can access the param value like this req.params.lastName in controller

Related

.on("ready") define guild id with mysql

I trying to code a simple customize statistic with command trought data base "mysql" and i have problem about define guildID in "Ready" function is the anyway to define it or i need search other solutions
const Discord = require("discord.js")
const { bot } = require('../index');
const { mysql } = require('../index')
bot.on('ready', async () => {
setInterval(function() {
let sql = 'SELECT * FROM stats WHERE guildID = ?'
mysql.query(sql, [guild.id], (err, results) => {
let allchannels = results.channelID
let guildid = results.guildID
setInterval(() => {
const guild = bot.guild.get(`${guildid}`)
var userCount = guild.memberCount;
const totalUsers = bot.channels.get(`${allchannels}`)
totalUsers.setName(`total members = ${userCount}`)
}, 20000);
})
}, 15000);
})
connection.query(sql, [guild.id], (err, results) => {
ReferenceError: guild is not defined
i want to code a statistic like StartIT v4 bot but idk is it possible in ready? i dont want on any restart my bot use command like !start statistic etc,
im glad if someone know how to fix it or have any solution
You problem is that guild is not defined, the bot Object has no guild only guilds a Collection where all guilds are listed. You can either fetch the id of the specific server and filter the collection, or what i think is better for your case loop throw the hole collection and set the statistics.
As for if its possisble, you can use bot.on guildCreate and guildDelete to listen when a bot joines a new server or leaves a server. I dont know what values you want to have in your statistics, but if you want an overview above all servers your bot is running on i would use the create and delete event.
Here you can see that the client (your bot) has no attribute guild
discord.js Client

Proper way of handling errors and sending JSON back for API

I am new to js/node/express, and I have been working on this application where I have the following code to handle user registration:
const Account = require('../models/Account.js')
module.exports = {
// TODO: Check why Postman hangs on POST request for this
async register (req, res, next) {
if (req.body.email && req.body.password) {
var newAccount = new Account()
newAccount.email = req.body.email
newAccount.password = newAccount.generateHash(req.body.password)
const account = Account.create({email: newAccount.email, password: newAccount.password}, function (err, res) {
if (err) {
console.log('could not insert. Check error.')
// CANT CALL res.status(400).send({ error: 'email already exists'})
res.status(500)
return next(err)
}
res.status(400).send({
error: 'exists'
})
})
console.log(`inserted account ${newAccount.email}`)
res.send(account.toJSON())
}
}
}
I read this post about how to properly send JSON data back in order to build a proper REST API but ran into some issues.
When I do the call to res.status(400) I get an error that res.status is not a function. Is that because res is not available in that if statement? If it isn't how then, do I properly send a 400 (or any error status) in a case like this?
I want to be able to send an error message if the saving into my mongo db fails, or send back the created user if the insertion was successful.
If there is anything out there that I can read Id love to read some of that as well.
When I do the call to res.status(400) I get an error that res.status is not a function.
That's because you are defining res as an argument to the callback in this line:
const account = Account.create({email: newAccount.email, password: newAccount.password},
function (err, res) {
And that res hides the higher scoped res. The solution is to not have a name conflict. Change the name of this res to be accountRes or something like that. You have to be aware of name conflicts in declared argument names when nesting inline functions.
It also looks like:
res.send(account.toJSON())
is in the wrong place. You will send that BEFORE Account.create() finishes its asynchronous work. That probably needs to be inside the callback.
Speaking of proper error handling, if this if (req.body.email && req.body.password) test fails, then you don't send any response at all. You need to always send some sort of response to an http request. I'd suggest adding an else to that if and send an appropriate response.

MEANJS Server controller list function

i have some problems changing my list function in the server controller of my MEANJS app. This is the export.list function in the server controller of my module:
exports.list = function(req, res) {
Wordset.find({ 'user':req.user._id }).sort('-created').populate('user', 'displayName').exec(function(err, wordsets) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(wordsets);
}
});
};
What it does is that it lists all the items from this module in the listview. In this case it shows all Wordset fromt this user. What i would like to change is that it should show Wordsets not depending on the user, but depending on another module (a user can create persons and each person should have his own wordsets). Lets say i have stored the person._id already, what changes do i need to do here to show only the Worsets for this specific person?
May be something like this (ofc. if Wordset has person field):
Wordset.find({ 'person': person._id })

Mongoose Populate with express res.json() breaks

So I'm selecting Activities from the mongodb and populating User for each.
var query = Activity.find(query).populate("user");
return query.sort({created:"desc"}).exec(function(err, activities) {
debugger;
if (!err) {
return res.json(activities);
} else {
res.status(400).json(err);
}
});
As you can see I have a debugger; breakpoint is there, When I'm pring activities it prints an array of activities with the user object populated.
Also when I'm calling something like activities[0].toJSON() I get everything good!
But the response comes back with the user property empty !
I looked into the source of express.response.json(OBJ) and saw this line:
var body = JSON.stringify(val, replacer, spaces);
val is my activities
When calling JSON.stringify(activities) it will create a json with an empty user field.. any suggestions ?
Try the lean option. That gives back plain JS objects with no mongoose weirdness. Also, your error handling seems a little awkward, can be simplified.
var query = Activity.find(query).populate("user");
query.sort({created:"desc"}).lean().exec(function(err, activities) {
if (err) return res.status(400).json(err);
res.json(activities);
});
I would go even further, not hard-coding error sending in routes but simply passing along via if (err) return next(err) to error-handling middleware defined elsewhere in your app. You can still set the status, then use detection in your middleware, something like this:
app.use(function(err, req, res, next){
err.status = err.status || 500;
res.status(err.status).json(err);
});

Simple Express program for querying a result

I have a snippet of Express code
Below what i am trying to do is pass the table name to keyName by extracting from the request
But I am facing deaslock
i wanted to know whether i am following proper protocols for JSON response
[Part-of-Express-Code]
app.get('/RestaurantDesc/:Key',function(request,response,next){
var keyName=request.query.Key;
var name_of_restaurants, RestaurantTimings;
async.series( [
// Get the first table contents
function ( callback ) {
connection.query('SELECT * FROM ',keyName, function(err, rows, fields)
{
console.log('Connection result error '+err);
name_of_restaurants = rows;
callback();
});
},
// Get the second table contents
function ( callback ) {
connection.query('SELECT * FROM RestaurantTimings', function(err, rows, fields)
{
console.log('Connection result error '+err);
RestaurantTimings = rows;
callback();
});
}
// Send the response
], function ( error, results ) {
response.json({
'restaurants' : name_of_restaurants,
'RestaurantTimings' : RestaurantTimings
});
} );
} );
I am getting the output as Cannot GET /RestaurantDesc/
Any Ideas
your route should be path, A path that you can access through GET request.
for ex: you should be able to access it through
http://example.com/RestaurantDesc/anyKeyHere
and in your code you have
var keyName = request.query.Key
req.query contains query variables see http://expressjs.com/api.html#req.query
So your keyName variable won't contain anyKeyHere.
req.params.Key will contain value anyKeyHere;
but you will need to pass it in url path.
if you need to pass key data in query you can do this.
app.get('/RestaurantDesc',function(request,response,next){
var keyName=request.query.Key;
});
and pass key like this in your url
http://example.com/RestaurantDesc/?Key=restaurnetkeyHere
Try going through guide in express site and understand routings and how it works.
If you getting "Cannot GET /RestaurantDesc/" is because you have not setup this route, try /RestaurantDesc/something. request.query is used for search terms, ie things that come after a questionmaek in a url. Use request.param.Key instead.
Also for best practices you should lowercase resource names and use the shorter req/res instead of request/response.