Express middleware undefined type - node.js

I am trying to create an authentication middleware for my express server and I get no Type errors in my IDE but when I try to complile I am getting TypeError: Cannot read properties of undefined (reading protect). The route works fine without the middleware and the middleware has no detectable linting issues. I am also using socket.io so I tried io.use(wrap(middleware)) on the off chance it would work and it didn't but that was a shot in the dark anyway, the problem seems unrelated. I've also tried replacing ALL relevant type declarations with any and got the same problem.
userController:
export const getMe = asyncHandler(async (req: IGetUserAuthInfoRequest, res: Response): Promise<void> => {
res.status(200).json(req.user)
})
RoutesController:
public static protect = asyncHandler(async (req: IGetUserAuthInfoRequest, res: Response, next: NextFunction): Promise<void> => {
let token: string
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
try {
token = req.headers.authorization.split(' ')[1]
const decoded: JwtPayload = jwt.verify(token, process.env.JWT_SECRET, { complete: true })
req.user = await UserModel.findById(decoded.id).select('-password')
next()
} catch (err) {
res.status(401)
throw new Error('Not authorised')
}
}
if (!token) {
res.status(401)
throw new Error('Not a valid token')
}
})
Extended express Request interface:
export interface IGetUserAuthInfoRequest extends Request {
user: any
}
userRouter:
userRouter.route('/me').get(RoutesController.protect, userController.getMe)
The error:
TypeError: Cannot read properties of undefined (reading 'protect')
at Object.<anonymous> (C:\Users\liams\dev\my-rest-server\src\routes\user.router.ts:8:46)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Module._compile (C:\Users\liams\dev\my-rest-server\node_modules\source-map-support\source-map-support.js:568:25)
at Module.m._compile (C:\Users\liams\AppData\Local\Temp\ts-node-dev-hook-8639111545614118.js:69:33)
at Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
at require.extensions.<computed> (C:\Users\liams\AppData\Local\Temp\ts-node-dev-hook-8639111545614118.js:71:20)
at Object.nodeDevHook [as .ts] (C:\Users\liams\dev\my-rest-server\node_modules\ts-node-dev\lib\hook.js:63:13)
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)
[ERROR] 20:08:00 TypeError: Cannot read properties of undefined (reading 'protect')
Any ideas what I'm missing?
EDIT: rather than posting everyline of my code here you can see it in the repo: https://github.com/dotDone/my-rest-server/tree/auth

Your RouteController is not defined yet when you use it in the user controller. ( Your architecture can be improved, but I will try to only answer your question, just know that there is a better way to organize all this )
Try the following
Turn UserRoutes to a class
import { Router } from 'express'
import * as userController from '../controllers/user.controller'
class UserRoutes {
constructor(routesController) {
this.userRouter: Router = Router();
this.routesController = routesController;
this.initRoutes();
}
initRoutes() {
userRouter.route('/').get(userController.getUsers).post(userController.createUser).put(userController.editUser).delete(userController.deleteUser)
userRouter.route('/me').get(this.routesController.protect, userController.getMe)
}
}
Then in your server.ts, create another function, call it initRoutes for example where you do something like this
constructor() {
this.startServer().then(() => this.startControllers()).then(() => this.initRoutes()).catch(err => console.log(err))
}
...
initRoutes() {
this.userRoutes = new UserRoutes(this.routesController);
}

Related

i cannot declare new property in request object of express

I'm trying to attach the new property to the request object in typescript.
this is the code :
import { request, Request, response, Response } from "express";
((req: Request, res: Response) => {
console.log(req.user);
})(request, response)
i'm declaring like this :
declare global {
namespace Express {
interface Request {
user: string;
}
}
}
and then I'm running it with ts-node. result is :
/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:843
return new TSError(diagnosticText, diagnosticCodes, diagnostics);
^
TSError: тип Unable to compile TypeScript:
x.ts:9:21 - error TS2339: Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
9 console.log(req.user);
~~~~
at createTSError (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:843:12)
at reportTSError (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:847:19)
at getOutput (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:1057:36)
at Object.compile (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:1411:41)
at Module.m._compile (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:1596:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
at Object.require.extensions.<computed> [as .ts] (/home/mahdi/Desktop/learn-stuf/test/node_modules/ts-node/src/index.ts:1600:12)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:827:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12) {
diagnosticCodes: [ 2339 ]
}
I tested too many answers of sites, but one of them did not work. please help.
First, I think your declare file got some problems.
edit the file like
export {}
declare global {
namespace Express {
interface Request {
user: string;
}
}
}
or
namespace Express {
interface Request {
user?: string
}
}
add directory that contains the declare file in tsconfig. Since I usually name it express.d.ts and place in src/types folder, in my case, tsconfig.json will be edited like this
{
"compilerOptions": {
"typeRoots": ["src/types"],
}
}
lastly, also add ts-node configuration in tsconfig.json. (not in compilerOptions)
{
"ts-node": {
"files": true
}
}
Are you maybe looking for #types/express ?
You can also fix it with intersection type :
function endpoint (req: Request, res: Response & {user: string;}) {
console.log(req.user);
}
But maybe you are looking for req.body.user, type Response<{user: string;}> ?

I was writing Discord bot with index.js and .env and I messed with this error while running this in terminal "node index.js"

I want develop my own discord bot here's the contents:
Index code
const { Client } = require("discord.js");
const { config } = require("dotenv");
// Declares our bot,
// the disableEveryone prevents the client to ping #everyone
const client = new Client({
disableEveryone: true
});
config({
path: __dirname + "/.env"
})
// When the bot's online, what's in these brackets will be executed
client.on("ready", () => {
console.log(`Hi, ${client.user.username} is now online!`);
// Set the user presence
client.user.setPresence({
status: "online",
game: {
name: "me getting developed",
type: "WATCHING"
}
});
})
// When a message comes in, what's in these brackets will be executed
client.on("message", async message => {
console.log(`${message.author.username} said: ${message.content}`);
});
// Login the bot
client.login(process.env.TOKEN);
Output
disableEveryone = true
^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: Invalid shorthand property initializer
at Module._compile (internal/modules/cjs/loader.js:891:18)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:991:10)
at Module.load (internal/modules/cjs/loader.js:811:32)
at Function.Module._load (internal/modules/cjs/loader.js:723:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1043:10)
at internal/main/run_main_module.js:17:11
Invalid shorthand property initializer indicates that you used an invalid property initializer. In this case, it looks like you used "=" instead of ":" to declare the property value "true" on property "disableEveryone".
Saving the code as shared and running it again should solve your problem.

Express : using await before bcrypt.compare gives error

I am trying to use bcrypt to compare user's password with stored password.
But Express is giving error is I use await before bcrypt.compare
Here is the code :
app.post ('/users/login', (req, res) => {
const user = users.find(user=> user.name === req.body.user)
if (user == null) {
return res.status(400).send('Can Not find user');
} else {
try{
if ( await bcrypt.compare(req.body.password, user.password)) {
res.send("Success");
} else {
res.send("Incorrect PAssword");
}
} catch {
return res.status(500).send('Some Error has occurred');
}
}
});
I am getting this error :
C:\Data\Ashish\projects\jwtAuthentication\app.js:32
if ( await bcrypt.compare(req.body.password, user.password)) {
^^^^^^
SyntaxError: Unexpected identifier
at Module._compile (internal/modules/cjs/loader.js:723:23)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
[nodemon] app crashed - waiting for file changes before starting...
Please help to find the mistake..
Regards,
Ashish
You forgot to add async to the callback function.
app.post ('/users/login', (req, res) => {
Should be:
app.post ('/users/login', async (req, res) => {
Await will work only with async functions.
It is different from the chrome console. In the console you can directly use await keyword, but in case of node.js, you need to specify async nature of the parent function in which you want to use await.
For further reference, you can refer to this link.

SyntaxError: Unexpected token function in async function?

Hi everyone I'm beginner in Nodejs and mongoose.I have tried to insert and retrieve the data in mongoose.I'm using async await function to execute one by one (sequence).can anyone help me? Thanks in advance....
i.e: I want to execute (Async await)concept (SEQUENCE STEP)
1.connect the db
2.create the user
3.find the user.
I'm getting the error :
async function calltaskone(){
^^^^^^^^
SyntaxError: Unexpected token function
at Object.exports.runInThisContext (vm.js:78:16)
at Module._compile (module.js:543:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:420:7)
at startup (bootstrap_node.js:139:9)
at bootstrap_node.js:535:3
Code for your reference:
'use strict';
const mongoose=require('mongoose');
const calldbconnect=()=>{
return new Promise((resolve,reject)=>{
if(true){
mongoose.connect('mongodb://vdsd:vdwdwh12dw3,#ds11dwdw.mlab.com:1w5664/vorganisation',{useNewUrlParser:true},(err,db)=>{
if(err){
console.log(err);
reject('Db is not connected');
}
else{
resolve('Db is connected');
}
});
}
});
}
const schemadesign=new mongoose.Schema({
clientName:String,
clientId:Number,
clientAddress:String
});
const modeldata=mongoose.model('clientInfo',schemadesign);
const data=[{
clientName:'VIGNESH Mack',
clientId:4128,
clientAddress:'UK'
},{
clientName:'VIGNESH Tokyo',
clientId:4988,
clientAddress:'USA'
}];
function calldatasave(){
return new Promise((resolve,reject)=>{
modeldata.create(data,(err,a,b)=>{
if(err){
reject(`Error occured while data saved ${err}`);
}
else{
resolve('Data saved successfully');
}
});
});
}
const calldatafind=()=>{
return new Promise((resolve,reject)=>{
if(true){
console.log('try to find');
modeldata.find({'clientId':4988},(err,data)=>{
if(err){
reject(`Error occured while find data: ${err}`)
}
else{
console.log(data);
resolve('Data found');
}
});
}
});
}
async function calltaskone(){
const a=await calldbconnect();
console.log(a);
const b=await calldatasave();
console.log(b);
const c=await calldatafind();
console.log(c);
}
calltaskone();
I believe you're using a older version of Node. Async functions are not supported by Node versions older than version 7.6. You can check here.
If you want to use async/await then you need to transpile using Babel for your node version.
Edit:
As you said you are using v7.3, you can use (from v7.0 to v7.5) the --harmony flag to enable the experimental features. To know more about the flag, check this out: What does `node --harmony` do?

node.js then() not working

I am new to node.js so I am trying to understand promises and wait on node.js. I want to print the file note.txt.
Here is my code
var fs = require('fs');
fs.readFile('note.txt','utf8').then(contents => console.log(contents))
.catch(err => console.error(err));
When I run above code. I get the following error.
fs.readFile('note.txt','utf8').then(contents => console.log(contents))
TypeError: Cannot read property 'then' of undefined
at Object.<anonymous> (/Applications/nodeApps/test/index.js:13:31)
at Module._compile (module.js:635:30)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:608:3
And I try another method for the same thing.
var fs = require('fs');
async function read_file(){
var file_data = await fs.readFile('note.txt','utf8');
return file_data;
}
console.log(read_file());
And I get following error
Promise { <pending> }
(node:6532) [DEP0013] DeprecationWarning: Calling an asynchronous function without callback is deprecated.
I get the same error when I run with --harmony. I m not sure if there is bug on my code or what is wrong. Please help me understand.
My Environment
Node version: v8.9.0
node -p process.versions.v8: 6.1.534.46
You're getting errors because fs.readfile doesn't return a promise; hence then doesn't exist. For you to use the function as a promise, you will need to wrap it up as a promise; you could use something like bluebird or Q.
Thank you for the answers. I learned that function must return promise in order to use then() and catch(). So the code should be like this
var fs = require('fs');
function read_file(){
return new Promise(function(resolve, reject) {
fs.readFile('note.txt','utf8',function(err,file){
if(err){
return reject(err);
}else{
resolve(file);
}
});
});
}
read_file().then(
(data)=>{
console.log('success: '+data);
}
).catch((err)=>{
console.log('error: ',err);
});
If you use NodeJs v10, try fs.promises:
var fs = require('fs').promises; // v10.0 use require('fs/promises')
fs.readFile('note.txt','utf8').then(contents => console.log(contents))
.catch(err => console.error(err));
If not, use readFileSync:
// This code can use for node v10 or lowwer
var fs = require('fs');
var data = fs.readFileSync('a.json');
console.log(data);
try to use the async await
function (async err => {
if (err) {
console.err ....}
await .... <other function included or comes after then .>
await ... <other function included>
})

Resources