How to properly give next() in the middleware in node app - javascript

I am trying to verify the bearer token which has been generated after the login request. I have segregated the codes for controllers, middlewares and routes.
The login is working fine and is able to generate the token but when I try to verify it I get the following error:
Error: Route.post() requires a callback function but got a [object Undefined]
at Route.<computed> [as post] (C:\Users\Desktop\loginapi\node_modules\express\lib\router\route.js:211:15)
at Function.proto.<computed> [as post] (C:\UsersDesktop\loginapi\ at Module.require (node:internal/modules/cjs/loader:1028:19)
at require (node:internal/modules/cjs/helpers:102:18) at Object.<anonymous> (C:\Users\Desktop\loginapi\index.js:15:20)
[nodemon] app crashed - waiting for file changes before starting...
Below is the complete Code:
Server.js //Main file
const express = require('express')
const app = express()
require('dotenv').config();
const port = process.env.PORT;
console.log(port)
//initialize middleware
app.use(express.json())
//import routes
const authRoutes = require('./src/routes')
// initialize routes
app.use('/abc', authRoutes)
// console.log();
//app start
const appStart = () => {
try {
app.listen(port, ()=> {
console.log(`The app is listening at http://localhost:${port}`)
})
} catch (error) {
console.log(`${error.message}`)
}
}
appStart()
routes/index/js
const { Router} = require('express')
const userController = require('../controllers/index')
const { verifyToken } = require('../middlewares/verifyTokens')
const router = Router()
router.post('/login', userController.login)
router.post('/profile',verifyToken ,userController.profile)
module.exports = router
middlewares/verifyTokens.js
// Function to verify whether the bearer token is correct or not
function verifyToken(req, resp, next) {
const bearerHeader = req.headers['authorization'];
if (typeof bearerHeader !== 'undefined') {
const bearer = bearerHeader.split(" ");
const token = bearer[1];
req.token = token;
next();
} else {
resp.send({
result: 'Invalid Token'
})
}
}
module.exports = verifyToken
contollers/index.js
const { sign } = require('jsonwebtoken')
const secret = process.env.SECRET;
//login function
const login = async (req, res) => {
payload = {
"email": "abc#gmail.com",
"password": "user123"
}
console.log(payload)
try {
sign(payload, secret, (err, token) => {
try {
res.json({
token
})
// console.log(typeof resp.json)
} catch (err) {
res.send(err.message);
}
})
} catch (error) {
console.log(error.message)
return res.status(500).json({
error: error.message
})
}
}
const profile = async (req,res) => {
try {
return res.status(200).json({
success: true,
message: 'In Profile',
})
} catch (error) {
console.log(error.message)
return res.status(500).json({
error: error.message
})
}
}
const userControllers = {
login,
profile
}
module.exports = userControllers
There is some problem with the middleware verifyTokens ,I have gone through other answers but I am not getting it. Can someone please point it out as to where I am going wrong. It will be very helpful. Thank you

Import verifyTokens without { } it will solve the problem.
In routes/index/js :
const verifyTokens = require('../middlewares/verifyTokens')

Instead of this
router.post('/login', userController.login)
router.post('/profile',verifyToken ,userController.profile)
try this one
router.post('/login',(req, res) => {
userController.login
});
router.post('/profile',
(req, res, next) => {
verifyToken
},
(req,res,next) => {
userController.profile
}
);

Related

Test a POST Http request from a local node server in REACT

I need to make unit tests for some post requests but i dont understand how.I tried with mswjs but the test passes because i'm missing something and i dont know what.I tried to test the requests in an usual way but i wasnt able to put my conditions there and it was sending only 200 status code..
To start with,this is my folder structure:
+main folder
++nodeServer
+++public
+++routes
++public
++src
+++tests
This is my try for testing the post request to /subscribe endpoint,where i should send an email as a payload and get the response that the payload was received succesefully.
subscribeFetch.test.js:
import {setupServer} from 'msw/node'
import {rest} from 'msw'
const handlers = [
rest.post("/api/subscribe",(req,res,context)=>{
if (!req.body || !req.body.email) {
return res(context.status(400).json({ error: "Wrong payload" }));
}
if (req.body.email === 'forbidden#email.com') {
return res(context.status(422).json({ error: "Email is already in use" }));
}
return res(
context.status(200),
context.json({email:'gigi#gmail.com'})
)
})
]
const server = setupServer(...handlers)
beforeAll(()=>server.listen())
afterAll(()=>server.close())
afterEach(()=>server.resetHandlers())
test('should send post request to the server',async()=>{
server.use(
rest.post('/api/subscribe',(req,res,ctx)=>{
return res(
expect (ctx.status()).toBe(200)
)
}
)
)
})
//export {handlers,rest}
This is the subscribe post request function that i need to test:
import { validateEmail } from './email-validator.js'
export const sendSubscribe = (emailInput) => {
const isValidEmail = validateEmail(emailInput)
if (isValidEmail === true) {
sendData(emailInput)
}
}
export const sendHttpRequest = (method, url, data) => {
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: data
? {
'Content-Type': 'application/json'
}
: {}
}).then(response => {
if (response.status >= 400) {
return response.json().then(errResData => {
const error = new Error('Something went wrong!')
error.data = errResData
throw error
})
}
return response.json()
})
}
const sendData = (emailInput) => {
sendHttpRequest('POST', '/api/subscribe', {
email: emailInput
}).then(responseData => {
return responseData
}).catch(err => {
console.log(err, err.data)
window.alert(err.data.error)
})
}
Files from the server:
app.js:
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const indexRouter = require('./routes/index');
const communityRouter = require('./routes/community');
const analyticsRouter = require('./routes/analytics');
const app = express();
global.appRoot = path.resolve(__dirname);
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/community', communityRouter);
app.use('/analytics', analyticsRouter);
module.exports = app;
index.js from routes folder in the server folder:
const express = require('express');
const router = express.Router();
const FileStorage = require('../services/FileStorage');
/* POST /subscribe */
router.post('/subscribe', async function (req, res) {
try {
if (!req.body || !req.body.email) {
return res.status(400).json({ error: "Wrong payload" });
}
if (req.body.email === 'forbidden#email.com') {
return res.status(422).json({ error: "Email is already in use" });
}
const data = {email: req.body.email};
await FileStorage.writeFile('user.json', data);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
/* GET /unsubscribe */
router.post('/unsubscribe', async function (req, res) {
try {
await FileStorage.deleteFile('user.json');
await FileStorage.writeFile('user-analytics.json', []);
await FileStorage.writeFile('performance-analytics.json', []);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
module.exports = router;
Please guys,help me write unit test for subscribe endpoint to match the conditions from index.js file from routes folder in the server folder,thank you in advance!
So,i got the expected result without any library,but i dont know if its a good aproach,but at least it works :
const app = require('../../../personal-website-server/app')
const request = require('supertest')
describe('POST /subscribe', () => {
it('should give 400 status code when email is empty', async () => {
const email = { email: '' }
const response = await request(app).post('/subscribe').send(email)
if (!request.body || !request.body.email) {
expect(response.status).toBe(400)
}
})
it('should give 422 status code when email is forbidden', async () => {
const email = { email: 'forbidden#gmail.com' }
const response = await request(app).post('/subscribe').send(email)
if (request.body === 'forbidden#gmail.com') {
expect(response.status).toBe(422)
}
})
it('should give 200 status code when email is valid', async () => {
const email = { email: 'gigi#gmail.com' }
const response = await request(app).post('/subscribe').send(email)
expect(response.error).toBe(false)
expect(response.status).toBe(200)
expect(response.body.body).not.toBeNull()
})
})

Firebase - ⚠ Error: Route.post() requires a callback function but got a [object Undefined]

So I am running into an issue while working my way through a Firebase / React tutorial and I just made it through the refactoring section which starts here: https://www.youtube.com/watch?v=m_u6P5k0vP0&t=5590s
Everything has gone well except my post function for posting one new Twitter-style update. and the error when trying to run firebase server I am getting is:
⚠ Error: Route.post() requires a callback function but got a [object Undefined]
at Route.<computed> [as post] (/Users/tmac/Programing/HolbertonFinal/MentorMatchingApp/firebase-fuctions/functions/node_modules/express/lib/router/route.js:202:15)
at Function.app.<computed> [as post] (/Users/tmac/Programing/HolbertonFinal/MentorMatchingApp/firebase-fuctions/functions/node_modules/express/lib/application.js:482:19)
at Object.<anonymous> (/Users/tmac/Programing/HolbertonFinal/MentorMatchingApp/firebase-fuctions/functions/index.js:10:5)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Module.require (node:internal/modules/cjs/loader:999:19)
at require (node:internal/modules/cjs/helpers:102:18)
at initializeRuntime (/Users/tmac/.nvm/versions/node/v17.3.0/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:655:29)
⚠ We were unable to load your functions code. (see above)
I'll try to get the relevant modules here but let me know if I am missing something and I can add it. I am very new to this and really appreciate all the help!
index.js
const functions = require("firebase-functions");
const app = require('express')();
const { postOneScream } = require('./handlers/screams'); // Not Working
const { signup, login } = require('./handlers/users');
const { FBAuth } = require('./util/fbAuth');
// Scream routes - Testing post functionality for social media feed posts
app.post('/screams', FBAuth, postOneScream); // Error: Route.post() requires a callback function but got a [object Undefined]
// Signup route
app.post("/signup", signup);
// Sign In route
app.post('/login', login);
// export api allows us to use express for our function formating
exports.api = functions.https.onRequest(app);
fbAuth.js
const { admin } = require('./admin');
// Check if user has a token for being logged in
module.exports = (req, res, next) => {
let idToken;
if(req.headers.authorization && req.headers.authorization.startsWith('Bearer ')){
idToken = req.headers.authorization.split('Bearer ')[1];
} else {
console.error('No token found');
return res.status(403).json({error: 'Unauthorized'});
}
admin.auth().verifyIdToken(idToken)
.then(decodedToken => {
req.user = decodedToken;
console.log(decodedToken);
return db.collection('users')
.where('userId', '==', req.user.uid)
.limit(1)
.get();
})
.then(data => {
req.user.handle = data.docs[0].data().handle;
return next();
})
.catch((err) => {
console.error('Error while verifying token', err);
return res.status(403).json({err})
})
}
screams.js
const { db } = require('../util/admin');
exports.postOneScream = (req, res) => {
const newScream = {
body: req.body.body,
userHandle: req.user.handle,
createdAt: new Date().toISOString()
};
db.collection('screams').add(newScream).then((doc) => {
res.json({ message: `document ${doc.id} created successfully` })
})
.catch((err) => {
res.status(500).json({ error: 'something went wrong' });
console.error(err);
})
};
Thanks again for any and all help, I am really trying to learn webdev but boy there is a lot and each step only shows me more how much I don't know :)
So, in index.js, you are importing "FBAuth" from "./util/fbAuth",
const { FBAuth } = require("./util/fbAuth");
but in './util/fbAuth', you are not exporting "FBAuth".
Modify your fbAuth file to something like this,
const { admin } = require('./admin');
// Check if user has a token for being logged in
module.exports.fbAuth = (req, res, next) => {
let idToken;
if(req.headers.authorization && req.headers.authorization.startsWith('Bearer ')){
idToken = req.headers.authorization.split('Bearer ')[1];
} else {
console.error('No token found');
return res.status(403).json({error: 'Unauthorized'});
}
admin.auth().verifyIdToken(idToken)
.then(decodedToken => {
req.user = decodedToken;
console.log(decodedToken);
return db.collection('users')
.where('userId', '==', req.user.uid)
.limit(1)
.get();
})
.then(data => {
req.user.handle = data.docs[0].data().handle;
return next();
})
.catch((err) => {
console.error('Error while verifying token', err);
return res.status(403).json({err})
})
}

Asynchronous function call is not working, synchronous is working

I have a router with the following route:
router.post('/login', async (req, res, next) => {
try {
console.log(req.body);
const { username, password } = req.body;
const identity = await userService.getUserInfo(username, password);
if (!identity.authenticated) {
return res.json({});
}
const requiredTenantId = process.env.TENANT_ID;
const tenant = identity.tenants.find((it) => it.id === requiredTenantId);
if (requiredTenantId && !tenant) {
return res.json({});
}
const userResponse = {
...identity,
token: jwt.sign(
identity,
envVars.getVar(envVars.variables.AUTH_TOKEN_SECRET),
{ expiresIn: '2h' }
)
};
return res.json(userResponse);
} catch (err) {
return next(err);
}
});
Which is basically an asynchronous function.
This is the working test sample:
const request = require('supertest');
const user = require('../../routes/user');
describe('Test user login path', () => {
test('If authorized, it should response with authorized JWT token', () => {
request(user).
post('api/user/login/').
send({
username: 'admin',
password: 'admin'
}).
expect(200);
});
});
If I add async before the function call and await before request user:
test('If authorized, it should response with authorized JWT token', async () => {
await request(user).
the test will fail with the following error:
connect ECONNREFUSED 127.0.0.1:80
Can somebody explain why it is like that? Because in the router I'm using the asynchronous route function.
That's because the supertest expects to be given an express application, not a router
You can create a test-purpose app, mount the user route:
const app = express();
app.use(bodyParser.json());
app.use("/api/user", user);
app.listen(3000);
and pass it to the request
await request(app)
.post("/api/user/login")
working example

404s for every Koa route (Typescript)

Problem
Setting up Auth Controllers
Using Bcrypt and JWT
All POST Calls to Koa 404ing
Calls to other routes working fine
Possibly a issue with scope of code.
import * as Router from 'koa-router';
import * as bcrypt from 'bcrypt';
import User from '../models/user';
const router: Router = new Router();
/**
* Signup new Users
*/
router.post('/signup', async ctx => {
const { username, password, email } = ctx.request.body;
bcrypt.hash(password, 10, (err, hash) => {
if (err) {
ctx.status = 500;
} else {
const user = new User({
username,
password: hash,
email,
});
user.save()
.then(result => {
ctx.status = 201;
})
.catch(err => {
if (err) {
ctx.response.status = 500;
}
});
}
});
});
/**
* Log in users
*/
router.post('/login', async ctx => {
const { email, password } = ctx.request.body;
User.findOne({ email }, (err, user) => {
if (err) {
ctx.status = 401;
ctx.body = 'Auth Failed.';
}
bcrypt.compare(user.password, password, (err, result) => {
if (err) {
ctx.status = 401;
ctx.body = 'Auth Failed.';
}
if (result) {
ctx.status = 200;
ctx.body = 'Auth Successful';
} else {
ctx.status = 401;
ctx.body = 'Auth Failed';
}
});
});
});
export default router;
I am not struggling to
generate passwords or save users to
the DB and I am receiving data into the
server from the controllers the only thing
is my server is not sending back anything but
a 404 error.
import * as Koa from 'koa';
import * as dotenv from 'dotenv';
import * as mongoose from 'mongoose';
import * as cors from '#koa/cors';
import * as bodyParser from 'koa-body';
import bookRouter from './routes/book';
import userRouter from './routes/user';
dotenv.config();
const app: Koa = new Koa();
mongoose.connect(process.env.MGO_URI, { useNewUrlParser: true }).catch(error => {
console.log(error);
console.log('\n application shutting down for safety \n');
process.exit(1);
});
// application wide middleware
app.use(cors());
app.use(bodyParser());
// application routes
app.use(userRouter.routes());
app.use(bookRouter.routes());
app.listen(3000);
console.log('Server running on port 3000');
First off, if you are using an async request handler you should use await. It makes the code a lot cleaner. I think this should work (although I'm not positive if bcrypt return a promise, but I think it does), for example:
router.post('/signup', async ctx => {
const { username, password, email } = ctx.request.body;
try {
let hash = await bcrypt.hash(password, 10);
const user = new User({ username, password: hash, email });
await user.save();
ctx.status = 201;
} catch(err) {
console.log(err); // TODO: handle err
ctx.status = 500;
}
});

Nodejs App works locally but only two route is working on Heroku

Hello all first and foremost this issue may seem like a duplicate but it is not as I have gone through other SO post relating to mine but it still didnt help and hence the reason I am making another. Please I need help, I have a nodejs back-end that is working locally without any issue. I uploaded it to heroku and now only two routes is working. All other routes are not working. I am able register, login and add new users.
This is for my add users routes that is working both locally and on heroku.
import mongoose from 'mongoose';
import { Router } from 'express';
import bodyParser from 'body-parser';
import User from '../model/user';
import { authenticate } from '../middleware/authMiddleware';
export default({ config, db }) => {
let api = Router();
// '/v1/user/add' - Create
api.post('/add', authenticate, (req, res) => {
let newUser = new User();
newUser.username = req.body.username;
newUser.email = req.body.email;
newUser.phonenumber = req.body.phonenumber;
newUser.profilepicurlicUrl = req.body.profilepicurl;
newUser.save(err => {
if (err) {
res.status(500).json({ message: err });
return;
}
res.status(200).json(newUser);
});
});
This is for my register user and login user that is working both locally and on heroku
import mongoose from 'mongoose';
import { Router } from 'express';
import bodyParser from 'body-parser';
import passport from 'passport';
import config from '../config';
import Account from '../model/account';
import UserDataExt from './extensions/userData-ext';
import async from 'async';
import crypto from 'crypto';
import { generateAccessToken, respond, authenticate } from '../middleware/authMiddleware';
var nodeMailer = require('nodemailer');
export default ({ config, db }) => {
let api = Router();
// '/v1/account/register'
api.post('/register', (req, res) => {
UserDataExt.findUserByEmail(req.body.email, (err, userData) => {
if (err) {
res.status(409).json({ message: `An error occured: ${err.message}`});
return;
} else if (userData) {
res.status(300).json({ message: `Email ${req.body.email} is already registered`});
}
// else {
Account.register(new Account({username: req.body.email}), req.body.password, function(err, account) {
if(err) {
res.status(500).json({ message: err });
return;
}
console.log("Registering new account");
passport.authenticate('local', { session: false })(req, res, () => {
res.status(200).send('Successfully created new account');
});
});
// }
});
});
// '/v1/account/login'
api.post('/login', (req, res, next) => {
UserDataExt.findUserByEmail(req.body.email, (err, userData) => {
if (err) {
res.status(409).json({ message: `An error occured: ${err.message}`});
return;
} else {
next();
}
});
}, passport.authenticate('local', { session: false, scope: [] }), (err, req, res, next) => {
if (err) {
res.status(401).json({ message: `Password is incorrect`});
return;
}
}, generateAccessToken, respond);
This is for my category route that is not working on heroku, but is working locally
import mongoose from 'mongoose';
import { Router } from 'express';
import Category from '../model/category';
import bodyParser from 'body-parser';
import { authenticate } from '../middleware/authMiddleware';
export default({ config, db }) => {
let api = Router();
// /v1/category/add Create
api.post('/add', authenticate, (req, res) => {
let newCategory = new Category();
newCategory.submittedById = req.body.submittedById;
newCategory.categoryTitle = req.body.categoryTitle;
newCategory.categoryDescription = req.body.categoryDescription;
newCategory.recommended = req.body.recommended;
newCategory.save(err => {
if (err) {
res.status(500).json({message: err});
return;
}
res.status(200).json({message: 'Category saved successfully'});
});
});
// /v1/category/ Read
api.get('/', authenticate, (req, res) => {
Category.find({}, (err, category) => {
if (err) {
res.status(500).json({message: `An erro has occured ${err.message}`});
return;
}
res.status(200).json(category);
});
});
This is my authenticate middleware code
import jwt from 'jsonwebtoken';
import expressJwt from 'express-jwt';
const TOKENTIME = 60*60*24*90;
const SECRET = "#######";
let authenticate = expressJwt({ secret: SECRET });
let generateAccessToken = (req, res, next) => {
req.token = req.token || {};
req.token = jwt.sign ({
id: req.user.id,
}, SECRET, {
expiresIn: TOKENTIME // 90 days
});
next();
}
let respond = (req, res) => {
res.status(200).json({
user: req.user.username,
token: req.token,
id: req.user._id
});
}
module.exports = {
authenticate,
generateAccessToken,
respond
}

Categories