Nodejs controller is being messy - javascript

I'm new to javascript, node.js (or backend at all). I am trying to create a controller for the login page requests and I am confused about getting data from the MYSQL table and User Authentication and working with JWT package !
In my Controller, I first check if the user input is available in the user table (with a simple stored procedure), then I compare the database password and the user input, after this I want to create a token and with limited time. (I have watched some tutorial videos about JWT and there is no problem with it), my main problem is to figure out how to write a proper controller with this functions?
I have 2 other questions:
1.Is it the right and secure way to get data from MySQL table inside the route? Or should I create a JS class for my controller? (I'm a bit confused and doubtful here)
2.Assuming that comparePassword() returns true, how can I continue coding outside of the db.query callback function scope? Because I have to execute comparePasssword() inside db.query callback
loginController.js :
const { validationResult } = require('express-validator');
const bcrypt = require('bcrypt');
const db = require('../../sqlConnection')
let comparePassword = (dbPass, inputPass) => {
bcrypt.compare(inputPass, dbPass, function(err, result) {
console.log(result)
});
}
// for get request
exports.getController = (req, res) => {
res.send('login')
}
// for post request
exports.postController = (req, res) => {
let errors = validationResult(req)
if(!errors.isEmpty()) {
res.status(422).json({ errors: errors.array() })
}
// find data from MYSQL table
let sql = `CALL findUser(?)`
db.query(sql, [req.body.username], (err, res) => {
if(err) console.log(err)
//console.log(Object.values(JSON.parse(JSON.stringify(res[0]))))
var data = JSON.stringify(res[0])
data = JSON.parse(data).find(x => x)
data ? comparePassword(data.password, req.body.password) : res.status(400).send('cannot find
user')
})
res.send('post login')
}
login.js :
const express = require('express')
const router = express.Router()
const { check } = require('express-validator');
const loginCont = require('../api/controllers/loginController')
router.route('/')
.get(
loginCont.getController
)
.post(
[
check('username').isLength({min: 3}).notEmpty(),
check('password').isLength({min: 4}).notEmpty()
],
loginCont.postController
)
module.exports = router

In my point of view, looks like there is no easy answer for your question so I will try to give you some directions so you can figure out which are the gaps in your code.
First question: MySQL and business logic on controller
In a design pattern like MVC or ADR (please take a look in the links for the flow details) The Controllers(MVC) Or Actions(ADR) are the entry point for the call, and a good practice is to use these entry points to basically:
Instantiate a service/class/domain-class that supports the request;
Call the necessary method/function to resolve what you want;
Send out the response;
This sample project can help you on how to structure your project following a design pattern: https://riptutorial.com/node-js/example/30554/a-simple-nodejs-application-with-mvc-and-api
Second question: db and continue the process
For authentication, I strongly suggest you to take a look on the OAuth or OAuth2 authentication flow. The OAuth(2) has a process where you generate a token and with that token you can always check in your Controllers, making the service a lot easier.
Also consider that you may need to create some external resources/services to solve if the token is right and valid, but it would facilitate your job.
This sample project should give you an example about how to scope your functions in files: https://github.com/cbroberg/node-mvc-api
Summary
You may have to think in splitting your functions into scoped domains so you can work with them in separate instead of having all the logic inside the controllers, then you will get closer to classes/services like: authenticantion, user, product, etc, that could be used and reused amount your controllers.
I hope that this answer could guide you closer to your achievements.

Related

trying to use express and redis to make a login web page

I'm trying to make a simple login page.I have to do it for university project.The problem is pretty simple, i'm trying to use redis to be the database for the users and passwords. The problem is that i can't extract the values out of the response that i get from redis.I got a docker running the redis image and every thing connect.In the example below im trying to make a simple boolean change from true to false according to the data inside the key (im using "a" as the key) but no matter what i do the value doesn't seem to change, it is note worthy that im very new to this and to js in particular, i read in the redis api that all of the funtions are asyncs i tried changing the code but it didnt help.
app.get('/enter', (req, res) => {
var username =req.query.user;
var password = req.query.pass;
ans = false
redis.get(username,function(err, reply) {
if(reply != null ) ans = true;
})
console.log(ans);
})
I just trying to verify that the key has a value, i tried to make a variable before and after the request but it isn't adjusting thanks for your time
I see you dont understand the very very basics of callbacks and asynchronouse behaviour of javascript.
Well you can code like this:
app.get('/enter', async (req, res) => {
var username =req.query.user;
var password = req.query.pass;
ans = false
let reply = await getUsername(username)
console.log(reply)
console.log(ans);
})
function getUsername(username) {
return new Promise((res, rej) => {
redis.get(username, function(err, reply) {
if(err) rej(err)
res(reply)
})
})
}
You can just promisfy your redis code with new Promise and then you can use async / await style on it
Otherwise you need to write your code in the callback witch leads to an callback hell if you have more code

Multiple parameters PUT - NodeJS - No ORM

I've made some API (NodeJS, db: PostgreSQL) for my Android app and now I'm facing problem with PUT. Ofc, API isn't anything special and it's made with express template, without ORM. I'm not backend dev, but I had to do that. But what is my problem... I've tried multiple times to make route, that allows me to pass 3 arguments. First one is ID (protege_patron), second is firstname (from input) and last one is lastname (from input).
router.put('/:firstname/:lastname', (req, res, next) => {
const protege_firstname = req.params.firstname
const protege_lastname = req.params.lastname
const { protege_patron } = req.body
pool.query(
'UPDATE proteges SET protege_patron = $1 WHERE (protege_firstname = $2 AND protege_lastname = $3)',
[protege_patron, protege_firstname, protege_lastname],
(error, results) => {
if (error) {
throw error
}
res.status(200).send(`User modified with ID: ${id}`)
}
)
})
I guess my problem is router.put('/:firstname/:lastname', but I just can't find any solution or anything that would help me. Most of examples use ORM or other stuff. Is there any solution, link to some hidden knowledge, anything? I know my code is... bad, still.

Node.js flat-cache, when to clear caches

I have a Node.js server which queries MySQL database. It serves as an api end point where it returns JSON and also backend server for my Express application where it returns the retrieved list as an object to the view.
I am looking into implementing flat-cache for increasing the response time. Below is the code snippet.
const flatCache = require('flat-cache');
var cache = flatCache.load('productsCache');
//get all products for the given customer id
router.get('/all/:customer_id', flatCacheMiddleware, function(req, res){
var customerId = req.params.customer_id;
//implemented custom handler for querying
queryHandler.queryRecordsWithParam('select * from products where idCustomers = ? order by CreatedDateTime DESC', customerId, function(err, rows){
if(err) {
res.status(500).send(err.message);
return;
}
res.status(200).send(rows);
});
});
//caching middleware
function flatCacheMiddleware(req, res, next) {
var key = '__express__' + req.originalUrl || req.url;
var cacheContent = cache.getKey(key);
if(cacheContent){
res.send(cacheContent);
} else{
res.sendResponse = res.send;
res.send = (body) => {
cache.setKey(key,body);
cache.save();
res.sendResponse(body)
}
next();
}
}
I ran the node.js server locally and the caching has indeed greatly reduced the response time.
However there are two issues I am facing that I need your help with.
Before putting that flatCacheMiddleware middleware, I received the response in JSON, now when I test, it sends me an HTML. I am not too well versed with JS strict mode (planning to learn it soon), but I am sure the answer lies in the flatCacheMiddleware function.
So what do I modify in the flatCacheMiddleware function so it would send me JSON?
I manually added a new row to the products table for that customer and when I called the end point, it still showed me the old rows. So at what point do I clear the cache?
In a web app it would ideally be when the user logs out, but if I am using this as an api endpoint (or even on webapp there is no guarantee that the user will log out the traditional way), how do I determine if new records have been added and the cache needs to be cleared.
Appreciate the help. If there are any other node.js caching related suggestions you all can give, it would be truly helpful.
I found a solution to the issue by parsing the content to JSON format.
Change line:
res.send(cacheContent);
To:
res.send(JSON.parse(cacheContent));
I created cache 'brute force' invalidation method. Calling clear method will clear both cache file and data stored in memory. You have to call it after db change. You can also try delete specified key using cache.removeKey('key');.
function clear(req, res, next) {
try {
cache.destroy()
} catch (err) {
logger.error(`cache invalidation error ${JSON.stringify(err)}`);
res.status(500).json({
'message' : 'cache invalidation error',
'error' : JSON.stringify(err)
});
} finally {
res.status(200).json({'message' : 'cache invalidated'})
}
}
Notice, that calling the cache.save() function will remove other cached API function. Change it into cache.save(true) will 'prevent the removal of non visited keys' (like mentioned in comment in the flat-cache documentation.

Feathers JS authentication with no email

Im looking for an authentication system where the user submits to an enpoint and a jwt is generated at this endpoint, im not sure how to implement this, my client side application does not make use of email address or stored information, it is in fact a dApp. I just need an endpoint that will calculate a value from a supplied seed phrase and a password if the processing of these values goes well ( and it nearly always will unless someone sends junk to the endpoint) then a jwt will be issued.. so far the out of box functionality with feathers cli means that i need to use local strategy and need an email address, I cant find any demos out there on this.. anyone got any pointers ? so far my auth is pretty default
const authentication = require('#feathersjs/authentication');
const jwt = require('#feathersjs/authentication-jwt');
const local = require('#feathersjs/authentication-local');
module.exports = function (app) {
const config = app.get('authentication');
// Set up authentication with the secret
app.configure(authentication(config));
app.configure(jwt());
app.configure(local());
// The `authentication` service is used to create a JWT.
// The before `create` hook registers strategies that can be used
// to create a new valid JWT (e.g. local or oauth2)
app.service('authentication').hooks({
before: {
create: [
authentication.hooks.authenticate(config.strategies)
],
remove: [
authentication.hooks.authenticate('jwt')
]
}
});
};
and heres my service:
// Initializes the `aerAuth` service on path `/userauthendpoint`
const createService = require('feathers-memory');
const hooks = require('./userauthendpoint.hooks');
module.exports = function (app) {
const paginate = app.get('paginate');
const options = {
name: 'userauthendpoint',
paginate
};
// Initialize our service with any options it requires
app.use('/userauthendpoint', createService(options) );
// Get our initialized service so that we can register hooks and filters
const service = app.service('userauthendpoint');
service.hooks(hooks);
};
I am relatively new to feathers but not to building auth systems (in PHP)
The Custom authentication strategy guide and the feathers-authentication-custom plugin probably allow to do what you are looking for.
It also depends on how you want to implement this. You can either use the custom strategy for every service (as in the case of the API key which has to be sent in the header with every request) or just before the /authentication service to allow creating a JWT (the issue here is that it needs to reference a userId or other entityId that exists in the database which you don't have).
The easiest way would be to go with the first options and a custom header (X-DAP-PASSWORD) which could look like this:
const custom = require('feathers-authentication-custom');
app.configure(authentication(settings));
app.configure(custom((req, done) => {
const password = req.headers['x-dap-password'];
if(checkPassword(req.app.get('seedPassphrase'), password)) {
// implement your own custom logic for loading and verifying the user
done(null, user);
} else {
done(new Error('Invalid passphrase'));
}
}));

NodeJs, pattern for sync developement

I am new with NodeJs and Express frameworks. I have understood that Node works with only one thread on the server side. So, I have noticed this causes me some problems in order to develop correctly my application.
In my routes folder, I have a file index.js.
This file manage the navigation asked by the user from app.js.
So I decided to create a route function "test".
In this function, I had just that code
exports.test = function(req, res){
res.render('test', {});
};
So simple, so easy. That's rend the template test.jade in my views folder. Greats !
But I wanna complexify the process. In this test route function, I want load some content from my MYSQL database.
For that, I have created a folder Models in the folders node_modules
Inside, I have only 2 file, the first mysqlConnection.js which exports the variable DB in order to make queries.
var mysql = require('mysql');
var DB = mysql.createConnection(
{
host : 'localhost',
user : 'root',
password : '',
database : 'test',
}
);
DB.connect();
module.exports = DB;
In the second file, articles_class.js, I just have
var DB = require('models/mysqlConnection');
var Article = function() {
this.getArticles = function()
{
DB.query('SELECT * FROM articles;', function(err, rows, fields)
{
if (err)
throw err;
else
{
console.log(rows);
return (rows);
}
});
}
}
module.exports = Article;
Go back in my route test function :
I just want to load from table "test" all the articles. Very basic. But not easy.
Why ?
Because before the query is finished, NodeJs respond to the client with the template render, but, unfornlty, without the rows loaded. Asynchronous problem ... Mysql doesn't block the Nodejs javascript Instruction.
The code of the function :
exports.test = function(req, res){
var Article = require('models/articles_class');
a = new Article();
articles = a.getArticles();
console.log(articles); // undefined
res.render('test', {});
};
I Found others subjects in stackoverflow which speak about this problem. Make sync queries, work with callbacks ect ..
But for, here, if I try to manage this problem with callbacks, That's cannot work ... Because I need to send to the client the template with articles but I can't block the process with a sync method.
I am very lost ... I don't understand how I have to build my application. I am not able to create a good proceed in order to manage the sql queries. There is a pattern or a specific method ?
Or perhaps I have to make only ajax requests from the client. I load the template "test". And in a javascript file in the public folder, I ask to the server to load me the articles content and wait success callback function ? it's not very clean ...
Thx for your answers. The others answers I have found didn't help me to understand how manage that with NodeJs.
Pass a callback to getArticles:
exports.test = function(req, res){
var Article = require('models/articles_class');
a = new Article();
a.getArticles( function( articles ) {
console.log(articles); // undefined
res.render('test', { articles: articles });
});
};
Changes to your get articles function:
var DB = require('models/mysqlConnection');
var Article = function() {
this.getArticles = function( callback )
{
DB.query('SELECT * FROM articles;', function(err, rows, fields)
{
if (err)
throw err;
else
{
console.log(rows);
callback && callback(rows);
}
});
}
}
module.exports = Article;
Express will only return the template through the open http connection once res.render() is called. So it's just a matter of passing it as a callback through your call stack, so it should only be called after you have your database rows.
As we are working with callbacks, they don't block your application.

Categories

Resources