Express.js two routes like signup and signin in single module - javascript

I need help while putting different functions like sign up, sign in, delete a profile, edit profile, in a single file named Users in express.
I have put signup over the '/' and now I am unable to find the way to go to the sign in function in users file.
for signup, I used the express method as
app.use('/signup' , Users)
and I wanted to know that how can I access the sign in function now
//this is the code in Users.js file
router.post("/", (req, res) => {
var user = new User();
user.name = req.body.name;
user.DOB = req.body.DOB;
user.email = req.body.email;
user.city = req.body.city;
user.password = req.body.password;
user.gender = req.body.gender;
user.image = req.body.image;
user.Phone = req.body.PhoneNumber;
user.MsgNumber = req.body.MsgNumber;
user.about = req.body.about;
user.JoinDate = new Date;
user.save(function(err, result) {
if (err) {
res.json({
status: err
})
} else {
res.json({
status: 'ok'
});
}
});
});
//now the second function of signin
router.post("/signIn", passport.authenticate("local"), (req, res) => {
if (usernotfound == 0) {
res.send(JSON.stringify(req.user));
} else {
res.send('Not Found')
}
// here is the code from the main server js file to send data to these functions
app.use('/signUp', users)
app.use('/signin', users)
{signup is on '/' so that is called directly as the
root function. now how can i access the signin function}

Not quite sure what you are looking for but you are using the same handler for different routes when you do this:
app.use('/signUp', users)
app.use('/signin', users)
What you are telling express here is "I want the same thing to happen when users go to signUp and signin"
You can have the users route in same file but the handlers need to be different.
index.js
const epxress = require('express')
const userRouter = require('./users')
const app = express()
app.use('/users, userRouter)
The index file is a simple express app which requires user.js
users.js
const expreess = require('express')
const router = express.Router()
router.post("/signIn", passport.authenticate("local"), (req, res) => {
// Your code for signing in
})
router.post('/signUp', (req, res) => {
// your code for signing up
})
module.exports = router
So users.js is a simple express router. So now visitors can go to /users/signIn and /users/signUp - basically they go to '/users' and get routed to the user.js file which has other routes defined /signIn and /signUp so the complete path becomes /users/signIn and /users/signUp
Another way would be to export two handlers in your users.js file. Something like
index.js
app.post('/signIn', users.signIn)
app.post('/signUp', users.signUp)
And then in your users.js
exports.signIn = function(req, res) {
// Your code for signin in
}
exports.signUp = function(req, res) {
// Your code for signing up
}

Related

Cannot access variable using await-async function

I tried using Async-Await in NodeJs RESTful API but I seem to get an error I cannot resolve.
Here is my db.js:
const User = require('../models/User'),
user = {};
user.findUserByUsername = async function (username) => {
try {
const user = await User.findOne({username});
if (user)
return {data: user, status: 200};
return {message: `Cannot find user with username: ${username}`, status: 404};
} catch (err) {
return err;
}
};
module.exports = user;
And here is my api.js:
const express = require('express'),
router = express.Router(),
user = require('../db/db');
router.get('/user', async (req, res, next) => {
const user = await user.findUserByUsername(req.query.username);
// ^
// Cannot access 'user' before initialization
if (!user.status)
return next(user);
res.status(user.status);
res.doc = user.status === 404 ? user.message : user.data;
next();
});
module.exports = router;
When making a HTTP request, my server is crashing at that point. Where is my mistake?
You're mixing your variable names up. You have user as an import, but you also have user as a variable you're trying to assign to as a result of findUserByUsername.
Use different variable names, and follow the capitalization convention for this sort of database lookup:
const express = require('express'),
router = express.Router(),
User = require('../db/db');
router.get('/user', async (req, res, next) => {
const user = await User.findUserByUsername(req.query.username);

Getting frequent error while passing data from form to a URL in NodeJS the error is cannot post /urlname

this is my from page where I post to a URL articles but it gives me error that cannot POST/URL name
every time I want to save a new article it gives me same error cannot post/URL name
<form action="/routes/articles" method="post">
//here I simply used a partials!
{{>form}}
</form>
this is code where I get data through post method that is mentioned and then it is saved to the database const express = require('express');
const router = express.Router();
const Article = require("../model/schema")
router.get('/', (req, res) => {
res.send('hey !!');
});
router.get('/new', (req, res) => {
res.render('articleGenerator');
});
router.get("/:id",(req,res)=>{
})
router.post("/",async(req,res)=>{
const newArticle = new Article({
title:req.body.title,
description:req.body.description,
markdown:req.body.markdown
})
//this code saves new article that is send from form page mentioned above
try {
newArticle = await newArticle.save();
res.redirect(`/articles/${newArticle.id}`)
} catch (error) {
res.render("/articleGenerator",{articles:newArticle});
}
})
this is my main file that i run Note that I have exported one route articlesjs that saves data.
module.exports = router;
const express = require('express');
const app = express();
const mongoose = require("mongoose");
this is for data base mongoose//
mongoose.connect("mongodb://127.0.0.1:27017/blogging-site",{
useNewUrlParser:true,
useUnifiedTopology:true,
useCreateIndex:true
})
//here i get the routes of page that is saving the data
const theRoutes = require('./routes/articles')
app.use('/theroutes', theRoutes);
app.set('view engine', 'hbs');
app.get('/', (req, res) => {
res.render('index');
});
app.listen(3000, () => {
console.log('server is up and running!!');
});

passport and serving files nodejs

i am using passport with google strategy for authentication
my folder structure:
views
home.html
enter.html (this has just one google+ button)
app.js
routes
auth.js (for google login)
i want the client to be directed to enter.html and not be able to use home.html if req.user is not set ( req.user is set when user is authenticated using google )
once authentication is done user should be redirected to home.html
app.use(express.static()) makes both of them available which is not what i want
the google login page comes by auth/google
and i also need to know what i should keep as the callback uri
in app.js
i have done mongodb configuration
i have done passport configuration
what to do next?
in auth.js
const router = require('express').Router();
const passport = require('passport');
router.route('/google')
.get(passport.authenticate('google', { scope: ["profile"] }));
router.route('/google/redirect')
.get(passport.authenticate('google'), (req, res, next) => {
// res.redirect what
});
module.exports = router;
To serve the home.html page you could redirect to a protected home route. Here an example of how I would go about implementing this.
auth.js
router.route('/google/redirect')
.get(passport.authenticate('google', { failureRedirect: '/' }), (req, res, next) => {
// Set to redirect to your home route / html page
res.redirect('/home')
});
To prevent users from going to home without authorization, you should also add a route guard to your /home route.
routes.js
const { checkAuth } = require('./guards'); // Protected routes
router.get('/home', checkAuth, async (req, res) => {
res.render('home')
});
guards.js
module.exports = {
checkAuth(req, res, next) {
if (req.isAuthenticated()) {
return next()
} else {
res.redirect('/')
}
},
}

Is it possible a single API handles multiple requests in Node JS?

My goal is to create an API that handles multiple requests. By doing this, I need to pass a string as an argument to the url of API like this:
// index.js in client
fetch(`http://localhost:4000/routerName/${tableName}`).then()
// router.js
router.get(`/${tableName_from_client_page}`, (req, res) => { // Do Something })
A problem is, the browser can't connect to the targeted pages unless I create a whole new APIs for every matching tableNames.
I want my API handles multiple requests by receiving the tableName as its /url.
Are there some tricks to solve this problem?
This is how my whole router looks like:
// Router
const express = require('express'),
db = require('./db.js'),
router = express.Router();
router.get('/table', (req, res) => {
db.loadTable('SELECT * FROM someTable', res);
}) // Handles only one request on the name of url; /table
router.get(`/${tableName_from_client_page}`, (req, res) => {
db.loadTable(`SELECT * FROM ${tableName_from_client_page}`, res)
}) // Handles multiple requests, depending on its argument.
module.exports = router;
// Router
const express = require('express'),
db = require('./db.js'),
router = express.Router();
router.get('/table', (req, res) => {
db.loadTable('SELECT * FROM someTable', res);
}) // Handles only one request on the name of url; /table
router.get('/tables/:tableName', (req, res) => {
db.loadTable(`SELECT * FROM ${req.params.tableName}`, res)
}) // Handles multiple requests, depending on its argument.
module.exports = router;
// Router
const express = require('express'),
db = require('./db.js'),
router = express.Router();
This API will only handle one request "/table".
router.get('/table', (req, res) => {
db.loadTable('SELECT * FROM someTable', res);
})
To handle multiple requests checkout below code
but make sure to write this API last in the route file, If you write this API before the "/table" API then your "/table" request will also be handled by this API.
router.get('/:table_name', (req, res) => {
db.loadTable(`SELECT * FROM ${req.params.table_name}`, res)
})
module.exports = router;

Trouble with authentication

I´m facing a confusion issue while implementing the authentication for my restful api using passport local strategy.
Note:
I got the authentication working successfully when I´m doing it all in my index.js. But I want to use in Classes for better Code separation.
I have a passport.js Module
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var mysql = require('mysql');
var dbconfig = require('./database');
var connection = mysql.createConnection(dbconfig.connection);
module.exports = function(passport) {
// passport needs ability to serialize and unserialize users out of session
passport.serializeUser(function (user, done) {
//console.log("SER");
console.log(user),
done(null, user);
});
passport.deserializeUser(function (user, done) {
console.log("XXXX");
console.log(user);
connection.query("SELECT * FROM users WHERE name = ? ",user.name, function(err, rows){
console.log("DER");
console.log(rows);
done(err, rows[0]);
});
});
// passport local strategy for local-login, local refers to this app
passport.use('local-login', new LocalStrategy(
function (username, password, done) {
console.log("hhh");
console.log(username);
connection.query("SELECT * FROM users WHERE name = ? ",username, function(err, rows){
console.log(rows);
return done(err, rows[0]);
});
})
);
// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.sendStatus(401);
}
};
This is my Controller Class:
class AuthenticateController {
constructor(router, passport) {
this.router = router;
this.registerRoutes();
this.passport = passport;
}
registerRoutes() {
this.router.post('/login/:username/:password', this.login.bind(this));
//this.router.get('/logout', this.logout.bind(this));
this.router.get('/content', this.content.bind(this));
}
login(req, res) {
this.passport.authenticate("local-login", { failureRedirect: "/login"}),
res.redirect("/content");
}
content(req, res ) {
console.log(req.user);
if (req.isAuthenticated()) {
res.send("Congratulations! you've successfully logged in.")
} else {
res.sendStatus(401);
}
}
isLoggedIn(req, res, next) {
console.log(req.user);
if (req.isAuthenticated())
return next();
res.sendStatus(401);
}
}
module.exports = AuthenticateController;
The Controller gets the router and passport fully configured as parameters from my index.js.
//index.js
var express = require('express')
, cors = require('cors')
, app = express()
, passport = require('passport')
, morgan = require('morgan');
require('./config/passport')(passport); // pass passport for configuration
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(require('express-session')({secret: 'vidyapathaisalwaysrunning',
resave: true,
saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use(cors());
var apiRouter = express.Router();
app.use('/api', apiRouter);
//
var apiV1 = express.Router();
apiRouter.use('/v1', apiV1);
var authenticateApiV1 = express.Router();
apiV1.use('/auth', authenticateApiV1);
var AuthenticateController = require('./controllers/authenticate');
var ac = new AuthenticateController(authenticateApiV1, passport); //pass in our fully configured passport
//If I call this /login instead of the /auth/login/ in the Controller Class it works!
//app.post("/login",
// passport.authenticate("local-login", { failureRedirect: "/login"}),
// function (req, res) {
// res.redirect("/content");
// });
What is working and what is not working
The Authentication in general is working. In my posted index.js you see app.post("/login", .... If I call this one the authentication is successfully and if I try to reach the restricted content in /auth/content/ req.user has a value (the user object) and I can successfully call req.isAuthenticated() .
BUT, If I use the authentication from /auth/login/username/password the req.user is undefined when trying to reach the restricted Content.
I get no error and the response of /auth/login/username/password/ HTTP Code 301 - 'redirecting to /content.
I have currently no idea what I´m doing wrong here and I´m pretty new to the topic of Node/express/ passport ..
Hope someone has an Idea. If you need something else to help me, just mention it in the comments and I will do my best to provide you everything you need.
Thanks
EDIT:
I recently tried to read the req.user in the login function and even there it is undefined
login(req, res) {
this.passport.authenticate("local-login", { failureRedirect: "/login"}),
console.log(req.user) //undefined
res.redirect("/content");
}
I guess it could be some async problem and I should use some callback functions, but I don´t know how to apply this in my login()
EDIT 2:
Another Issue I´m facing is the integration of the isLoggedIn() request.
If I do this:
registerRoutes() {
this.router.get('/', this.isLoggedIn, this.getUsers.bind(this));
this.router.get('/:id', this.getSingleUser.bind(this));
}
it results in 401 - Unauthorized
A console.log(req.user); in the isLoggedIn() results in undefined.
But if I call the first route without calling isLoggedIn() and do console.log(req.user); the user object exists.
The correct use of callback with passport authentication for local strategy can be as below:
function(req, res, next){
passport.authenticate('local-login', function(err, user, info){
if(err)
return logger.log('error', err);
if(user)
req.login(user, function(err){
if(err) return next(err);
return res.json({'success': true});
});
if(!user)
return res.json({'error':true, 'message': info.message, 'type': info.type});
})(req, res, next);
}
Please note the use of req.login() to explicitly set user in session.
The only thing I'm finding strange is that your route declarations are different.
In the AuthenticateController the route is declared as:
this.router.post('/login/:username/:password', ...
While in index.js, the route is simply declared as
app.post("/login", ...
How is your client submitting the login credentials to the server? If it is by form, like the tutorial, could it be that having :username and :password declared as route params but being sent by form messes with passport?
Try registering the route exactly like index.js
this.router.post('/login', ...
EDIT:
I've found another dicrepancy. In AuthenticateController the res.redirect("/content"); is not wrapped inside a callback. So it is being executed before Authenticate finishes running.
In the index.js example, passport is being used as a route middleware:
app.post("/login",
passport.authenticate("local-login", { failureRedirect: "/login"}),
function (req, res) {
res.redirect("/content");
});
While in the passport.js it is inside the callback. Consider declaring it in the route:
registerRoutes() {
this.router.post('/login', this.passport.authenticate("local-login", { failureRedirect: "/login"}), this.login.bind(this));
(...)
}
login(req, res) {
res.redirect("/content");
}
O, better yet, why not use passport's option to declare both success and failure redirects, since that seems to be all that you are doing:
login(req, res) {
this.passport.authenticate("local-login", { successRedirect: "/content", failureRedirect: "/login" });
}
You are passing this.login.bind(this) as a middleware to this.router.post('/login/:username/:password', this.login.bind(this)); but login(req, res) only responds to the request with res.redirect("/content"); i.e. redirecting to /content
So like you said, you need to supply a callback that does something with the user that is returned from passports middleware verify callback.
app.post("/login",
passport.authenticate("local-login", { failureRedirect: "/login"}),
function (req, res) {
console.log(req.user); // log user in console
res.json({user: req.user}); // send user as json response
});
The custom callback mentioned by #divsingh is if you want to explicitly have control of setting the session, error messages and redirecting the request. Any other information can be found under http://passportjs.org/docs

Categories

Resources