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

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

Related

How can a function return an array of validators and also call next()?

I need a function that takes the request body and conditionally creates the validators that will be used on the request. I figured the best way to do this is by creating middleware but I'm running into a problem with express-validator. For express-validator to work the middleware has to return an array of my validators but if I do this I can't call next() and the request doesn't get handled.
// This will fail because I can't call next
const validatorMiddleware = (req, res, next) => {
const {
isFooRequired,
isBarRequired,
} = req.body;
return concat(
isFooRequired && createValidator('foo'),
isBarRequired && createValidator('bar'),
)
}
With the way I'm going about this I basically need a function that calls next() AND returns the array of validators.
I understand express-validator has a way to conditionally add validation rules but there doesn't seem to be an easy way to do this in bulk. I'd have to do this individually with each validation chain which is a huge pain and kind of gross if you ask me. I have several optional fields which are dependent on a lot of validation and I want to do something like this:
const addressValidators = (service) => [
body(`${service}.address.lineOne`).notEmpty().withMessage('Address cant be empty'),
body(`${service}.address.city`).notEmpty().withMessage('city cant be empty'),
body(`${service}.address.state`).isIn(allowedStates).withMessage('invalid state'),
body(`${service}.address.zipCode`).isPostalCode('US').withMessage('invalid zip code'),
];
In case anyone has this same problem I do, here's the solution I found. With express-validator you can run validations imperatively so I created the middleware you see below. Inside my constructValidators function I use the request body to see which fields are present and create my validation chain accordingly.
const validateMiddleware = async (req, res, next) => {
const validationList = constructValidators(req.body);
await Promise.all(validationList.map((validation) => validation.run(req)));
const errors = validationResult(req);
if (errors.isEmpty()) {
return next();
}
res.status(400).json({ errors: errors.array() });
return null;
};
Remember, 3 hours of troubleshooting could save you 10 minutes of reading documentation!

Problem extracting data from NEDB database Node.JS

I have a NEDB Datastore called users which contains one line of information. I call a fetch request to retrieve the users from the server and I can tell that the request is being processed by debugging. However, the users.find() is not working and I have no idea why. When I tried the same code with an alternate datastore, it worked fine.
Here is my Javascript code:
//Client side JS
async function extractUsers() {
const userJ = await fetch('/getUser');
let user = await userJ.json();
header.innerHTML = "Welcome " + user + "!";
}
//Server Side JS
const users = new Datastore('users.db');
users.loadDatabase();
app.get('/getUser', (req, res) => {
users.find({}, (err, data) => {
res.json(data);
})
});
If you have any idea why this is happening or need more information, please let me know. Thanks!
I simply deleted the users.db file and restarted the server, manually re-entering the data and it seemed to work.

Node Express - Getting a Cannot GET or request returning html page

I am making a backend api with node/express and am running into an error. I've tried many different approaches as well as looked at many different questions on here, but none seem to fix my problem. As far as I can tell my routes are structured properly, but they simply don't work. Perhaps I'm missing something super obvious, but I'm at a loss.
Bellow is a simplified version of my index.js where I start my node server:
const movies = require("./routes/movies");
app.use("/api/movies/", movies);
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Listening on port ${port}...`));
And then in my movies.js I have several endpoints:
// DOES WORK - returns movies with the specifed object
router.get("/genre/:id", async (req, res) => {
const movies = await Movie.find({ genres: req.params.id });
if (!movies)
return res
.status(400)
.send(`No movies with genre of id ${req.params.id} could be found.`);
res.send(movies);
});
// DOESN'T WORK - returns main html page
router.get("/tmdbid/:id", async (req, res) => {
const movie = await Movie.findOne({
tmdbID: req.params.id,
});
if (!movie)
return res
.status(400)
.send(`No movies with tmdbID of ${req.params.id} could be found.`);
if (res.status(404)) res.send("Route not found");
res.send(movie);
});
// DOESN'T WORK - returns Cannot GET /api/movies/title/{title}
router.get("/title/:title", async (req, res) => {
const movie = await Movie.find({
title: { $regex: new RegExp(req.params.title, "i")
},});
if (!movie)
return res
.status(400)
.send(`The movie with name of ${req.params.title} could not be found.`);
res.send(movie);
});
I'm not sure what needs to be done here. All of these share similar syntax, but each result in a different response. None of them log any errors to the terminal either. I know for sure general refactoring should be done, but as far as the problem at hand goes, I can't wrap my head around why the last two aren't working. Lastly, I have several other endpoints in the this file, all of which are working fine. Just these two have issues.
Add a console.log statement to check whether the endpoint is hit or not. The code logic in your code sample above sounds right. However, I would try formatting the code batter.
if (!movie){
return res.status(400).send(`No movies with genre of id ${req.params.id} could be found.`);
}
Also, make sure you do not forget to restart your node js server.
What are those return statements doing there? and you could improve your if statements as well like such ->
try {
const movie = await Movie.findOne({
tmdbID: req.params.id,
});
if (!movie) {
res
.status(400)
.send(`No movie(s) could be found.`);
} else {
res
.status(200)
.send(movie);
}
} catch(err) {
res.send(500);
}
I eventually found my answer and it was simply a mistake I had in the url when calling the endpoint, not in the endpoint's code itself. Rather than calling to localhost:5000, I was calling to localhost:3000, which is probably why it was returning the index.html of my react app.
So, my code works as is. Perhaps not the best structure ever, but as long as it works, I'm happy.
Still not sure why the /title/:title endpoint wasn't working and then suddenly was. That remains a mystery.

Nodejs controller is being messy

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.

Trying to return a string value from a function and save it to mongoDB doesn't work

I am so frustrated. I have been trying to fix this nasty bug since yesterday but there is no progress. I wonder what am I doing wrong.
This is what I want to do.
After the user submits the form which has enctype of "multipart/form-data" I want to grab the image that he has uploaded, put that into my MinIO database ( really similar to AWS S3 ) and then generate a link that will be the user's profile link. The link generates properly but I can't find a method to save it to the Account.pictureUrl value. Your help will be highly appreciated. Thank you!
THE CODE HAS BEEN REMOVED DUE TO PRIVACY CONCERNS
It's not a bug. It's a feature. JavaScript IO is asynchronous. Your best bet is to make url return a promise, so you can take advantage of async/await. MinIOClient methods return a promise if no callback is passed, so use that.
// If a custom image was selected by the client set the picture URL to Firebase's CDN
const url = async () => {
// If the user has selected a file
if (req.file) {
// Upload user image to the database
await MinIOClient.fPutObject("local", `${req.body.email}.png`, req.file.path, {
"Content-Type": req.file.mimetype
});
// Getting the link for the object
const presignedUrl = await MinIOClient.presignedGetObject("local", `${req.body.email}.png`, 24 * 60 * 60)
return presignedUrl;
}
// If the user didn't select an image return a random image link(string) that will be used to serve default avatars from the server
else {
return avatarLinks[Math.floor(Math.random() * avatarLinks.length)];
}
};
Then modify the controller
router.post("/", upload.single("avatar"), async (req, res) => {
const pictureUrl = await url();
let Account = new AccountSchema({
// ... other values
pictureUrl
});
});

Categories

Resources