Possible to pass a parameter into Express' app.use() - node.js

I have my Node/Express server running. I have the main server.js file where most of the code is for the server. Now I want to separate out the routes into a separate file. I have done this before using app.use(routes). But the problem is, I want to pass a string in for one of the routes to use.
Here is my server.js code:
// other imports
import routes from './routes.js';
const app = express();
...
const port = Number.parseInt(process.env.PORT, 10) || 3001;
const serverType = process.env.NODE_ENV === 'production' ? 'Production' : 'Test';
const statusMsg = `${serverType} Node server for external facing web server on ${port}`;
// i want `routes` to have access to `statusMsg`
app.use(routes);
Then in routes.js:
import express from 'express';
const router = express.Router();
router.get('/', (req, res) => res.status(200).send(statusMsg);
export default router;
I use serverType and port elsewhere in server.js, else I would just move all that code to routes.js.
Update
Adding in updated routes.js as I understand it with suggestion from jonrsharpe.
import express from 'express';
const router = express.Router();
const createRoutes = (statusMsg) => {
router.get('/', (req, res) => res.status(200).send(statusMsg);
};
export default createRoutes;

You can separate the server logic, routes logic, and business logic (usually inside a separate file called a controller).
inside the server file try blow code:
const express = require('express');
const app = express();
const bodyParser = require('body-parser')
require('dotenv').config();
const connectDB = require('./config/config')
const cookieParser = require('cookie-parser')
const authRoutes = require('./routes/authRoutes')
const categoryRoutes = require('./routes/categoryRoutes')
const cors = require('cors');
connectDB();
app.use(bodyParser.json());
app.use(cookieParser());
app.use(cors());
//Route Mounting
app.use('/', authRoutes);
app.use('/', categoryRoutes);
app.listen(process.env.PORT, ()=>{
console.log(`Server is running on PORT: ${process.env.PORT}`)
})
Then create a separate file authRoute.js and do the following code
const express = require('express')
const { registerUser, loginUser, getAllUsers, logoutUser} = require('../controllers/authController')
const router = express.Router()
const {isAuthenticatedUser, isAuthorizedRoles} = require('../middleware/auth')
router.route('/user/new').post(registerUser);
router.route('/user/login').post(loginUser);
router.route('/users').get(getAllUsers);
router.route('/account/logout').get(logoutUser);
module.exports = router;
lastly to write the business logic create file authController.js and place the following code.
const User = require('../model/userSchema');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
require('dotenv').config();
exports.registerUser = async (req, re, next)=>{
let password = req.body.password;
password = await bcrypt.hash(password, 10);
const newUser = req.body;
newUser.password = password;
try {
const user = await User.create(newUser);
if(user){
res.json({
success:true,
user
});
}
} catch (error) {
console.log(error);
}
}
exports.loginUser = async function(req, res){
const email = req.body.email;
const password = req.body.password;
if(!email || !password){
return res.json({
success:false,
message:'Please provide the email & Password'
})
}
const user = await User.findOne({email:email});
if(!user){
return res.json({
success:false,
message:'user with this email not found in database'
})
}
const isPasswordMatch = await bcrypt.compare(password, user.password);
if(!isPasswordMatch){
return res.json({
success:false,
message:'Your password is wrong...'
})
}
const token = jwt.sign({ _id: user._id }, process.env.JWT_SECRET, { expiresIn: process.env.JWT_EXPIRY_TIME });
res.cookie('token', token, {httpOnly:true, expires:new Date(Date.now() + 60*60*1000 )}).json({
success:true,
message:'You are logged in! Enjoy',
})
}
exports.getAllUsers = async (req, res, next)=>{
res.json({
success:true,
data:[
{
"id":1,
"name":"Yasir",
"qual":"MCS",
"age":32
},
{
"id":2,
"name":"Tabish",
"qual":"BS",
"age":21
},
{
"id":3,
"name":"Ahmed",
"qual":"BSCS",
"age":32
},
{
"id":4,
"name":"Hassan",
"qual":"MCS",
"age":33
}
]
})
}
exports.logoutUser = async (req, res, next)=>{
res.cookie('token', null, {expires:new Date(Date.now())}).json({
success:true,
message:'You are loggedOut',
})
}
This is the way you can have separation of concerns.

Related

Node/Express cannot get url "Cannot GET /api/auth/register"

I am trying to create a register page. when I route its shows Cannot GET /api/auth/register same thing happened when I route login and others too. i use postman to throw data it's shown 5000 internet server error.
how to solve route problem for register
// tested REGISTER i used it to test this code is runing or not in tutorial this code was runnign and show in register path is "ok"
// tested REGISTER
const express = require("express");
const router = express.Router();
const User = require("../models/User");
router.get("/register", async (req, res) => {
//create new user
const user = await new User({
username:"admin",
email:"admin#gmail.com",
password: "123456"
});
//save user and respond
await user.save();
res.send("Hello")
});
module.exports = router;
index.js
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");
const userRoute = require("./routes/users");
const authRoute = require("./routes/auth");
const postRoute = require("./routes/posts");
dotenv.config();
mongoose.connect(
process.env.MONGO_URL,
{ useNewUrlParser: true,
useUnifiedTopology: true
},
() => {
console.log("Connected to MongoDB");
}
);
//middleware
app.use(express.json());
app.use(helmet());
app.use(morgan("common"));
app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.use("/api/posts", postRoute);
app.listen(8000, () => {
console.log("Backend server is running!");
});
auth.js here the login and register file
const express = require("express");
const router = express.Router();
const User = require("../models/User");
const bcrypt = require("bcrypt");
//REGISTER
router.post("/register", async (req, res) => {
try {
//generate new password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password,salt);
//create new user
const newUser = new User({
username: req.body.username,
email: req.body.email,
password: hashedPassword,
});
//save user and respond
const user = await newUser.save();
res.status(200).json(user);
} catch (err) {
res.status(500).json(err)
}
});
//LOGIN
router.post("/login", async (req, res) => {
try {
const user = await User.findOne({ email: req.body.email });
// make sure user is not empty {} or [];
if (!user) res.status(404).json("user not found");
const validPassword = await bcrypt.compare(req.body.password,
user.password)
// make sure password is not empty {} or [];
if(!validPassword) res.status(400).json("wrong password");
res.status(200).json(user)
} catch (err) {
res.status(500).json(err)
}
});
module.exports = router;

Using express session to share information across different routes

I am wondering if anyone could help me please.
I have a react app that contains dialogflow (google's chatbot platform). I would like to share information in a user route to a dialogflow fulfillmentRoute using express-session. Here is my main server.js file. In the server.js I have declared an express-session
server.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const passport = require('passport');
const path = require('path');
var cors = require('cors')
const users = require('./routes/api/users');
const db = require('./config/keys').mongoURI;
require('./models/Users');
const app = express();
const session = require('express-session')
// Body parser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cors());
require('./routes/fulfillmentRoutes')(app);
app.use(session({secret: 'ssshhhhh'}));
// Connect to MongoDB
mongoose
.connect(db)
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
// Passport middleware
app.use(passport.initialize());
// Passport Config
require('./config/passport')(passport);
// Use Routes
app.use('/api/users', users);
// Server static assets if in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server running on port ${port}`));
In the user.js route file, I then have this to save an email into a session variable;
user.js
router.post(
'/',
passport.authenticate('jwt', { session: false }),
(req, res) => {
sess = req.session;
var emails = req.user.email;
sess.emails;
res.json({ msg: 'Users Works' })
res.json({
id: req.user.id,
firstname: req.user.firstname,
lastname: req.user.lastname,
email: req.user.email,
week: req.user.week,
age: req.user.age
});
}
);
In my dialogflow fullfillment route file, I have the following;
fulfillmentRoutes.js
const {WebhookClient, Payload, Card} = require('dialogflow-fulfillment');
const express = require('express');
const chatbot = require('../chatbot/chatbot');
const mongoose = require('mongoose');
const passport = require('passport');
const keys = require('../config/keys');
const sourceFile = require('./api/users.js');
const User = require('../models/User');
module.exports = app => {
var router = express.Router();
app.post('/api/df_text_query', async (req, res) => {
let responses = await chatbot.textQuery(req.body.text, req.body.userID, req.body.parameters);
res.send(responses[0].queryResult);
});
app.post('/api/df_event_query', async (req, res) => {
let responses = await chatbot.eventQuery(req.body.event, req.body.userID, req.body.parameters);
res.send(responses[0].queryResult);
});
app.post('/', async (req, res) => {
const agent = new WebhookClient({ request: req, response: res });
async function welcome(agent) {
let user = await User.findOne({'email': sess.emails});
if (user !== null ) {
responseText = `${sess.emails}`;
}
agent.add(responseText);
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
agent.handleRequest(intentMap);
});
return router;
}
In the welcome async function in fulfillment.js route, I use sess.emails that was declared in the user.js routes file. However the variable comes back undefined. Any guidance or help will be appreciated please.
Thanks
In your user.js, sess.emails; is not being assigned any variable.
Can you try replacing it sess.emails = emails; and check if the emails field is undefined?

Could not able to post data on node server

I am trying to hit http://localhost:5000/api/auth/ with post request using postman but it says "cannot post api/auth".
I am using mongo db and node js server.js
server.js file:
const express = require('express');
var connectDB = require('./config/db');
const app = express();
//connect database
connectDB();
// initializing middleware
app.use(express.json({extended: false}));
app.get('/', (req,res) =>
res.json({msg:'Hellow we are here'}));
//Define Routes
app.use('api/auth', require('./routes/auth'));
app.use('/api/users', require('./routes/users'));
app.use('/api/contacts', require('./routes/contacts'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log ("server running at port 5000"));
Here is the auth file:
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const {check, validationResult} = require('express-validator');
const config = require('config');
const User = require('../models/User');
//#route GET api/auth
//#desc Get logged in user
//#access private
router.get('/', (req, res)=> {
res.send('Get logged in suser');
});
//#route POST api/auth
//#desc Auth user and get token
//#access public
router.post (
'/',
[
check('email', 'Please enter a valid email').isEmail(),
check('password', 'password required').exists(),
],
async (req, res)=> {
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({errors: errors.array()});
}
const {email , password} = req.body;
try{
let user= await User.findOne({email});
console.log(user);
if(!user)
{
return res.status(400).json({msg:"Invalid credentials"});
}
const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch)
{
return res.status(400).json({msg:"Invalid credentials"});
}
const payload = {
user: { id: user.id }
};
jwt.sign(payload,
config.get('jwtSecret'),
{expiresIn: 36000},
(err, token) => {
if (err)
{ throw err;}
res.send({token});
});
}
catch (err) {
console.error(err.message);
res.status(500).send('server error');
}
});
module.exports = router;
There's a missing leading slash where you define the routes. It is
//Define Routes
app.use('api/auth', require('./routes/auth'));
but it should be
//Define Routes
app.use('/api/auth', require('./routes/auth'));

Route declared properly but still getting a Could not get any response error

I have making an API using express and node.
Here is my app.js
const express = require('express');
const bodyParser = require('body-parser');
const dotenv = require('dotenv');
// setup dotenv to read environment variables
dotenv.config()
// Load Environment Varibles
const env = require('./utils/env');
// INIT MONGODB CONNECTION
require('./mongoose');
// create a new express application
const app = express();
// setup bodyparser middleware to read request body in requests
// we're only reading JSON inputs
app.use(bodyParser.json());
// Listen to API routes
const apiRoutes = require('./routes')
app.use('/api', apiRoutes);
// Start listening to requests
app.listen(env.PORT, () => {
console.log(`Server started on PORT ${env.PORT}`);
});
And here is the API routes that are being imported
const express = require('express');
const apiController = require('./apiController');
const apiValidator = require('./apiValidator');
const router = express.Router();
router.post('/login', apiValidator.loginUserValidator, apiController.loginUserController);
router.get('/rand', (req, res) => {
res.send('Some randon text');
});
module.exports = router;
Here is the middleware
const {
failureResponse
} = require('./../utils/response');
const errorcodes = require('./../utils/errorcodes');
const loginUserValidator = (req, res, next) => {
const user = req.body;
if (!user.username) {
return res.status(400).json(failureResponse(errorcodes.ERROR_INVALID_BODY_PARAMETER, "Invalid username"));
}
if (!user.password) {
return res.status(400).json(failureResponse(errorcodes.ERROR_INVALID_BODY_PARAMETER, "Invalid password"));
}
if (user.authTokens) {
delete user.authTokens;
}
next();
};
module.exports = {
loginUserValidator
};
Here is the controller
const User = require('./../models/user');
const {
successResponse,
failureResponse
} = require('./../utils/response');
const errorcodes = require('./../utils/errorcodes');
const loginUserController = async (req, res) => {
try {
const user = req.body;
// find if the user already exists
const existingUser = await User.findOne({
username: user.username
});
if (existingUser) {
// user exists. generate token and login user
console.log('Existing user login');
const token = existingUser.generateAuthToken();
return res.status(200).json(successResponse(token));
} else {
console.log('New user login');
const savedUser = await new User(user).save();
const token = savedUser.generateAuthToken();
return res.status(200).json(successResponse(token));
}
} catch (e) {
console.log(e);
return res.status(400).json(failureResponse(errorcodes.ERROR_SERVER_ERROR, "Unable to login user"));
}
};
module.exports = {
loginUserController
};
Here the issue is when I try to hit the login route from Postman, I am getting an error which says Could not get any response.
But when I hit the rand route, the output is correct.
So the issue isn't the arrangement of the code.
Why am I not able to use the login route here?

Mongo/express cannot load route (Unexpected '<' in postman)

Been trying to get user user object by id from parameters, using User.findById and cannot access this route.
Postman response: Cannot GET /users/get/ with status 404 (not found) which is wierd.
Postman JSON response:
Unexpected '<'
Been using express-promise-router but also tried with default express.Router();
Here is my code:
routes/users.js
const express = require('express');
const router = require('express-promise-router')();
const passport = require('passport');
const router1 = express.Router();
require('../passport');
const { validateBody, schemas } = require('../helpers/routeHelpers');
const UsersController = require('../controllers/users');
const passportSignIn = passport.authenticate('local', { session: false });
const passportJWT = passport.authenticate('jwt', { session: false });
router.route('/signup')
.post(validateBody(schemas.authSchema), UsersController.signUp);
router.route('/signin')
.post(validateBody(schemas.authSchema), passportSignIn, UsersController.signIn);
router.route('/get/:id')
.get(UsersController.getUser);
router.route('/secret')
.get(passportJWT, UsersController.secret);
controllers/users
module.exports = router;
const JWT = require('jsonwebtoken');
const User = require('../models/user');
const { JWT_SECRET } = require('../configuration');
const signToken = (user) => {
return JWT.sign({
iss: 'CodeWorkr',
sub: user.id,
iat: new Date().getTime(), // current time
exp: new Date().setDate(new Date().getDate() + 1) // current time + 1 day ahead
}, JWT_SECRET);
};
module.exports = {
signUp: async (req, res) => {
const { email, password } = req.value.body;
// Check if there is a user with the same email
const foundUser = await User.findOne({ 'local.email': email });
if (foundUser) {
return res.status(403).json({ error: 'Email is already in use' });
}
// Create a new user
const newUser = new User({
method: 'local',
local: {
email: email,
password: password
}
});
await newUser.save();
// Generate the token
const token = signToken(newUser);
// Respond with token
return res.status(200).json({ token });
},
signIn: async (req, res) => {
// Generate token
const token = signToken(req.user);
res.status(200).json({ token });
},
getUser: async (req, res) => {
User.findById(req.params.id)
.then((user) => {
res.status(200).json({ user });
console.log('test');
});
},
secret: async (req, res) => {
console.log('I managed to get here!');
res.json({ secret: 'resource' });
}
};
server.js
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const passport = require('passport');
const db = require('./configuration/config').mongoURI;
const dbTest = require('./configuration/config').mongoURITest;
mongoose.Promise = global.Promise;
if (process.env.NODE_ENV === 'test') {
mongoose.connect(dbTest, { useMongoClient: true });
} else {
mongoose.connect(db, { useMongoClient: true });
}
const app = express();
app.use(cors());
app.use(passport.initialize());
app.use(passport.session());
// Middlewares moved morgan into if for clear tests
if (!process.env.NODE_ENV === 'test') {
app.use(morgan('dev'));
}
app.use(bodyParser.json());
// Routes
app.use('/users', require('./routes/users'));
// Start the server
const port = process.env.PORT || 3001;
app.listen(port);
console.log(`Server listening at ${port}`);
Other post routes works fine,

Resources