Hi everyone I'm learning about NodeJS and I'm having trouble importing between files
userController.js file
import userService from "../services/userService";
const userController = {
show: (request, response) => {
response.send(userService.show);
}
}
export default userController;
userService.js file
const userService = {
show: () => {
return 1;
}
}
export default userService;
I'm sure my path is correct
This is the error displayed in the console
internal/process/esm_loader.js:74
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/path_here/services/userService' imported from /path_here/controllers/userController.js
at finalizeResolution (internal/modules/esm/resolve.js:285:11)
at moduleResolve (internal/modules/esm/resolve.js:708:10)
at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:819:11)
at Loader.resolve (internal/modules/esm/loader.js:89:40)
at Loader.getModuleJob (internal/modules/esm/loader.js:242:28)
at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:73:40)
at link (internal/modules/esm/module_job.js:72:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
I tried to recall my knowledge but couldn't find the problem. Please help me check. Thanks
see do it like that
const file= required("./filename");
Related
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 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);
}
I am using NextJs and it's serverless functions.
I have a api route /api/blog/write, it is a protected route. Only authorize users can access it. For this i defined a middleware which check if request is comeing from a authorize user then processed other wise redirect request to login page.
api/blog/write.js
import requiredLogin from "#middleware/required-login";
const index= (req, res) => {
const cookies = parseCookies({req}).ts
res.statusCode = 200
return res.json({ status: 'Your first blog' })
}
export default requiredLogin(index);
#middleware/required-login.js
import { parseCookies } from 'nookies';
import jwt from "jsonwebtoken";
const JWT_KEY = process.env.JWT_KEY;
const requiredLogin = (handler) => (req,res)=>{
const token = parseCookies({req}).ts;
jwt.verify(token,JWT_KEY,(err,dev)=>{
if(err) return res.status(401).redirect("/auth?auth=signin")();
return handler(req,res);
})
}
module.exports = requiredLogin;
Using the above code for required-login.js gives me
status code : 500 and error is ReferenceError: parseCookies is not defined.
When i just replace return handler(req,res); in required-login.js with return res.status(200).send(dev) then i am getting expected result.
error consoled by node is
ReferenceError: parseCookies is not defined
at index (C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\.next\server\pages\api.js:110:19)
at C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\.next\server\pages\api.js:151:12
at C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\node_modules\jsonwebtoken\verify.js:223:12
at getSecret (C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\node_modules\jsonwebtoken\verify.js:90:14)
at Object.module.exports [as verify] (C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\node_modules\jsonwebtoken\verify.js:94:10)
at C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\.next\server\pages\api.js:148:25
at apiResolver (C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\node_modules\next\dist\next-server\server\api-utils.js:8:7)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async DevServer.handleApiRequest (C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\node_modules\next\dist\next-server\server\next-server.js:45:397)
at async Object.fn (C:\Users\Rahul kumar\desktop\Projects\dev\bdevg\node_modules\next\dist\next-server\server\next-server.js:37:176)
parseCookies is not defined in api/blog/write.js, and you use it there.
Since Node.JS (and JavaScript itself) doesn't expose variables defined in one file to another file that has be "required" by that file, you cannot access parseCookies in api/blog/write.js.
You must import it there as well.
// You must import `parseCookies`!
import { parseCookies } from 'nookies';
import requiredLogin from "#middleware/required-login";
const index= (req, res) => {
// You use parseCookies on the following line,
// so you have to import it.
const cookies = parseCookies({req}).ts
res.statusCode = 200
return res.json({ status: 'Your first blog' })
}
export default requiredLogin(index);
I'm using nestjs and I was trying to create a custom decorator:
import { createParamDecorator, ExecutionContext } from '#nestjs/common';
import { User } from './user.entity';
export const GetUser = createParamDecorator(
(data, ctx: ExecutionContext): User => {
const req = ctx.switchToHttp().getRequest();
return req.user;
},
);
The decorator is used here:
#Post('/test')
#UseGuards(AuthGuard())
test(#GetUser() user: User) {
console.log(user);
}
But I get the following error:
[Nest] 15053 - 26/03/2020, 13:28:19 [ExceptionsHandler] ctx.switchToHttp is not a function +61625ms
TypeError: ctx.switchToHttp is not a function
at /Users/nelson.larios/Documents/nestjs/nestjs-task-management/dist/auth/get-user.decorator.js:5:21
at /Users/nelson.larios/Documents/nestjs/nestjs-task-management/node_modules/#nestjs/core/router/router-execution-context.js:115:35
at resolveParamValue (/Users/nelson.larios/Documents/nestjs/nestjs-task-management/node_modules/#nestjs/core/router/router-execution-context.js:143:31)
at Array.map (<anonymous>)
at pipesFn (/Users/nelson.larios/Documents/nestjs/nestjs-task-management/node_modules/#nestjs/core/router/router-execution-context.js:148:45)
at /Users/nelson.larios/Documents/nestjs/nestjs-task-management/node_modules/#nestjs/core/router/router-execution-context.js:36:36
at InterceptorsConsumer.intercept (/Users/nelson.larios/Documents/nestjs/nestjs-task-management/node_modules/#nestjs/core/interceptors/interceptors-consumer.js:10:20)
at /Users/nelson.larios/Documents/nestjs/nestjs-task-management/node_modules/#nestjs/core/router/router-execution-context.js:45:60
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async /Users/nelson.larios/Documents/nestjs/nestjs-task-management/node_modules/#nestjs/core/router/router-proxy.js:8:17
Any thoughts?
Thanks
Prior to version 7.x, Custom Decorators were static, and thus did not get the ExecutionContext passed to them. In v7.x release, this has been added.
As mentioned in comments on the OP's question, you need to upgrade to this version to get the example in the documentation working.
In my Nest.js based application, I'm trying to use one configuration file to define all configuration for an application.
The configuration.json file looks like this:
{
"environment": "development",
"backendPort": 8080,
"appRootPath": ".",
...more configuration...
}
And in my Nest.js application's main.ts is:
import { NestFactory } from "#nestjs/core";
import configuration from "../configuration.json";
import { AppModule } from "./app.module";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(configuration.backendPort);
}
bootstrap();
I have enabled TypeScript's resolveJsonModule feature as mentioned in TypeScript 2.9 Release notes and VS code successfully recognized the import and provides IntelliSense and type checking.
But when I try to start the app via
ts-node -r tsconfig-paths/register src/main.ts
I get an error:
(node:5236) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'backendPort' of undefined
at d:\CodeDev\NestCMS\backend\src\main.ts:10:36
at Generator.next (<anonymous>)
at fulfilled (d:\CodeDev\NestCMS\backend\src\main.ts:4:58)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
at Function.Module.runMain (module.js:695:11)
at Object.<anonymous> (d:\CodeDev\NestCMS\backend\node_modules\ts-node\src\_bin.ts:177:12)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
(node:5236) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:5236) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Is there a way to define application port in an elegant way like I tried?
I don't want the port number to be hard-coded in the main.ts file. I want it to be configurable by some option to allow me to deploy the same application build to different environments where the only thing differing will be the configuration.json.
Yes. Use this - https://docs.nestjs.com/techniques/configuration part of NestJS docs to create ConfigService. You can replace dotenv with json if you want. Then:
import {NestFactory} from '#nestjs/core';
import {ConfigService} from 'src/config/config.service';
import {AppModule} from './app.module';
let bootstrap = async () => {
const app = await NestFactory.create(AppModule);
const configService: ConfigService = app.get(ConfigService);
await app.listen(configService.getPort);
};
bootstrap();
Now you can inject ConfigService in most part of your code + whle loading you can validate it using Joi. Hope this helps.
Workaround in 2021:
main.ts, NestJS v8.0.4
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '#nestjs/config';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const configService: ConfigService = app.get<ConfigService>(ConfigService);
const port = configService.get('APP_PORT');
await app.listen(port);
}
bootstrap();
Profit!
Try https://www.npmjs.com/package/neconfig for elegant config NestJs app.
Just register NeconfigModule in your AppModule:
import { Module } from "#nestjs/common";
import { NeconfigModule } from 'neconfig';
import * as path from 'path';
#Module({
imports: [
NeconfigModule.register({
readers: [
{ name: 'env', file: path.resolve(process.cwd(), '.env') },
],
}),
],
})
export class AppModule { }
Then use it like that:
import { Logger } from '#nestjs/common';
import { NestFactory } from '#nestjs/core';
import { ConfigReader } from 'neconfig';
import { AppModule } from './app.module';
(async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = app.get(ConfigReader);
const port = config.getIntOrThrow('PORT');
// const port = config.getInt('PORT', 3000);
await app.listen(port);
Logger.log(`Listening on http://localhost:${port}`);
})();
I have even better approach for doing that, and even simpler than this config service, so basically check my repo: https://github.com/neoteric-eu/nestjs-auth there is an example in src/config/index.ts how it works, package dotenv is quite nice, but dotenv-safe is far better, because if you're missing some values you won't know about that after you start a server! So basically your package.json script for development might looks like:
"develop": "node $NODE_DEBUG_OPTION -r ts-node/register -r dotenv-safe/config src/index.ts"
and then use and example of repo from above, regards!