RESTful API access token mechanism - javascript

I'm developing a JavaScript/MySQL RESTful API for a business manager system using Express, Body-parser and MySQL. Currently, I am working on access tokens. Before any API call, the body must include an API key that is being verified by the API. In every API call function, I first check if the access token exists and if so, the API executes MySQL commands and sends back results.
The important thing is that I want to create a function that checks whether the access token exists and returns true or false. However, I can't figure out how to return this boolean value from the conn.query() method. Any help will be very much appreciated, I am desperate.
Here is my code:
function checkApiKey(apiKey) {
let sql = "SELECT * FROM apikeys WHERE apikey = '" + apiKey + "'";
conn.query(sql, (err, results) => {
if (err) throw err;
if (results.length > 0) return true;
return false;
});
}
app.get("/api/users",(req, res) => {
if (checkApiKey(req.body.apiKey)) {
let sql = "SELECT * FROM users";
let query = conn.query(sql, (err, results) => {
if (err) throw err;
res.send(results);
});
}
});
However, the checkApiKey() method returns undefined...

Your checkApiKey function returns undefined, because your logic returns true or false within sql's callback function.
I'd recommend another approach, using checkApiKey as middleware function:
const checkApiKey = (req, res, next) => {
conn.query("SELECT * FROM apikeys WHERE apikey = ?", [req.body.apiKey], (err, result) => {
if (err) throw err
if (results)
next() // continue to next router function
else
res.status(403).end('Unauthorized') // resolve with 403
})
}
app.get("/api/users",
checkApiKey, // middleware auth function
(req, res) => {
conn.query("SELECT * FROM users", (err, results) => {
if (err) throw err;
res.send(results)
})
})

Related

How to create a loop for SELECT function, to keep data updated?

I'm using an Oracle database, and every time it updates, the server doesn't understand this update and needs me to drop it for it to update the data.
const express = require('express');
const oracledb = require('oracledb');
const app = express();
var cors = require('cors')
app.use (cors())
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
// Connection details for the Oracle database
const connectionString = 'dbprod';
const user = 'sapiensproducao';
const password = 'fabrica';
// Connect to the database
oracledb.getConnection(
{
connectionString: connectionString,
user: user,
password: password
},
function(err, connection) {
if (err) {
console.error(err.message);
return;
}
console.log('Connection was successful!');
// Execute a SQL query
const query = 'SELECT CODEMP,CODORI,NUMORP,SEQEOQ,DATREA,HORREA,CODPRO,CODDER,QTDRE1,QTDRFG,CODLOT,OBSEOQ from USU_VPROEXT ORDER BY DATREA DESC, HORREA DESC';
connection.execute(query, [], (err, result) => {
if (err) {
console.error(err.message);
return;
}
console.log('Query was successful!');
console.log()
// Render the HTML template and pass the query results as a local variable
app.get('/teste', (req, res) => {
res.json(result.rows)
});
});
}
);
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
I thought of creating a loop for this SELECT function, but how can I create it?
How can I keep running this select in a loop, to keep the data always updated?
In the structure of your web server, you only ever query the database once and then create an endpoint to serve that data. Instead, create an endpoint which queries the data whenever it's invoked. Which may look more like this:
// define the endpoint
app.get('/teste', (req, res) => {
// within the endpoint, query the database
oracledb.getConnection(
{
connectionString: connectionString,
user: user,
password: password
},
function(err, connection) {
if (err) {
console.error(err.message);
// DON'T DO THIS, return an actual response to the user
return;
}
console.log('Connection was successful!');
const query = 'SELECT CODEMP,CODORI,NUMORP,SEQEOQ,DATREA,HORREA,CODPRO,CODDER,QTDRE1,QTDRFG,CODLOT,OBSEOQ from USU_VPROEXT ORDER BY DATREA DESC, HORREA DESC';
connection.execute(query, [], (err, result) => {
if (err) {
console.error(err.message);
// DON'T DO THIS, return an actual response to the user
return;
}
console.log('Query was successful!');
console.log();
// return the results to the user
res.json(result.rows);
});
});
});
The key difference here is that instead of wrapping the endpoint in the query, you wrap the query in the endpoint. So every time the endpoint is invoked it re-queries the database.
Please also note the comments for your error handling. If you just return; from the function and never return a response to the client, the client will just hang until it times out. Return an actual response, which can include error codes, messages, anything you like. Even just res.json(false); would be better than no response at all.

Handle duplicates with express.js

So I am trying to create a login for the first time with express and react using Postgres. My user can be added to the database so I jumped into handling duplicates. I am using the findUserByEmail function to find my email and then, in my routes, calling that function before posting the email. I hope you guys can help me, I've been 1 week with this.
This is my queries.js where I :
const findUserByEmail = email => {
return pool.query("SELECT * FROM users WHERE email = $1", [email]);
};
const createUser = (request, response) => {
const date_created = new Date();
const { username, email, password } = request.body;
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
pool.query(
`INSERT INTO users (username, email, password, date_created) VALUES ($1, $2, $3, $4 )`,
[username, email, hash, date_created],
(error, results) => {
// console.log("---------->", email);
if (error) {
throw error;
}
response.status(201).send(`User added with ID: ${results.insertId}`);
}
);
});
});
};
and this is my index.js:
// ...Other connection code
//Routes
app.get("/users", queries.getUsers);
app.get("/user/:id", queries.getUserById);
app.post("/signup/user", (req, res, next) => {
console.log(req.body.email, "----------1");
queries
.findUserByEmail(req.body.email)
.then(user => {
console.log(user.rows.length);
if (user.rows.length < 0) {
res.status(400).send("this email is already in use");
} else {
console.log("Hello");
queries.createUser;
}
})
.catch(err => {
console.log(err);
res.status(500).send("Something went wrong");
});
});
app.put("/user/:id", queries.updateUser);
app.delete("/user/:id", queries.deleteUser);
app.listen(port, () => {
console.log(`App running on port ${port}.`);
});
Is not giving me an error, but when I submit a new user, keeps posting forever and does not change.
My post request worked till now without using the findUserByEmail.
Thanks for your help.
You have no guarantee that findUsersByEmail will find anything, even if there is a previous call, creating a user. The reason is that the query creating the user may not have returned yet.
You need database constraints to deal with this.
Put a unique constraint on the email field and handle duplicate exceptions correctly.

Node.js Express execute inside app.post()

I have a problem right now that I can't solve by myself. I assume you know more here. I'm just getting started.
By using the following code I'm getting a list of customers:
app.get("/customers", customers.findAll);
I wanted to add authentication. But now I don't know how to execute "customers.findAll" and get the value as JSON.
app.get("/customers", verifyToken, (req, res) => {
jwt.verify(req.token, 'justAtest, (err, authData) => {
if (err) {
res.sendStatus(403);
} else {
// execute customers.findAll
}
});
});
Customers is integrated via a requirement
const customers = require("../controllers/customer.controller.js");
The contents are as follows:
exports.findAll = (req, res) => {
Customer.getAll((err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving customers."
});
else res.send(data);
});
};
Do you have any ideas?
Thank you in advance.
Grettings
Rok
You achieve that using something called "middleware". Explore it since it is very important.
Basically :
app.get("/customers", verifyToken,customers.findAll);
Wherre verify token is a funtion that has 3 parameters: req, res and 3rd one called "next".
So your verify token function would look something like:
(req, res,next) => {
jwt.verify(req.token, 'justAtest, (err, authData) => {
if (err) {
res.sendStatus(403);
} else {
next();
}
});
}
I took it from your snippet. Basically if you want to jump to customeeers.finalAll, just call "next" and it jumps to next function :D.

how to pass mysql result to variable to render in template engines

I want to store mysql result to a variable, so i can pass to the template engine. I have multiple mysql queries and need to save every query result to different variables.
I am using Node JS and express JS
Below is my code (app.js)
var mysql = require('mysql');
var db = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database : 'my_db'
});
db.connect(function(err) {
if (err) throw err;
console.log('Database connected');
});
app.get('/', (req, res) => {
var emp_result;
var task_list_result;
db.query('SELECT * FROM emp', function (error, results, fields) {
if (error) throw error;
emp_result = results;
});
db.query('SELECT * FROM task_list', function (error, results, fields) {
if (error) throw error;
task_list_result;
});
res.render('dashboard',{"emp_res" : emp_result, "task_res" : task_list_result});
});
I am expecting that result should be store in a variable;
Using async await here to handle the asynchronous network calls. I f you want to use callback function, you should chain it one inside the other.
const {promisify} = require('util');
app.get('/', async (req, res) => {
const query = promisify(db.query).bind(db);
const emp_result = await db.query('SELECT * FROM emp')
const task_list_result = await db.query('SELECT * FROM task_list')
res.render('dashboard',{"emp_res" : emp_result, "task_res" : task_list_result});
});
Using Promise.all to make calls in parallel, as they are not dependent on each other, it increases the performance, you can use the below code-
const {promisify} = require('util');
app.get('/', async (req, res) => {
const query = promisify(db.query).bind(db);
const [emp_result, task_list_result] = await Promise.all([db.query('SELECT * FROM emp'), db.query('SELECT * FROM task_list')]);
res.render('dashboard',{"emp_res" : emp_result, "task_res" : task_list_result});
});
Using callback function, as you were using -
app.get('/', (req, res) => {
db.query('SELECT * FROM emp', function (error, results, fields) {
if (error) throw error;
const emp_result = results;
db.query('SELECT * FROM task_list', function (error, results, fields) {
if (error) throw error;
const task_list_result = results;
res.render('dashboard',{"emp_res" : emp_result, "task_res" : task_list_result});
});
});
});
You can use any of these, but second one is the best approach to follow.

Organize MongoDB request on Node.JS

I'm actually creating a chat like Discord with servers and channels using Node.JS, MongoDB and Mongoose.
Actually, my structure is this one:
https://github.com/copostic/My-Simple-Chat/tree/master/models
But to get the conversations, I have to make so much nested functions and I would like to know if there was a better way to organize my code..
Here's the code with the nested functions, I'm trying to get the message list of each channel of each server:
"use strict"
const Server = require('../models/server'),
Channel = require('../models/channel'),
Message = require('../models/message'),
User = require('../models/user');
exports.getChannels = function (req, res, next) {
// Only return one message from each conversation to display as snippet
Server.find({members: req.session._id})
.select('_id')
.exec(function (err, servers) {
if (err) {
res.send({ error: err });
return next(err);
}
servers.forEach(function (server) {
Channel.find({ serverId: server })
.exec(function (err, channels) {
// Set up empty array to hold conversations + most recent message
let fullConversations = [];
channels.forEach(function (channel) {
Message.find({
'channelId': channel._id
})
.sort('creationDate')
.limit(1)
.populate({
path: "author",
select: "profile.firstName profile.lastName"
});
.exec(function (err, message) {
if (err) {
res.send({
error: err
});
return next(err);
}
fullConversations.push(message);
if (fullConversations.length === conversations.length) {
return res.status(200).json({
conversations: fullConversations
});
}
});
});
});
});
});
};
Thanks a lot

Categories