nest js this.instance.use is not a function - node.js

I studying serverless nest.js with aws lambda
When I run serverless offline and send the request, an error occurred.
[Nest] 11048 - 2021. 07. 14. 오후 7:02:11 [NestFactory] Starting Nest application...
[Nest] 11048 - 2021. 07. 14. 오후 7:02:11 [InstanceLoader] AppModule dependencies initialized +16ms
[Nest] 11048 - 2021. 07. 14. 오후 7:02:11 [ExceptionHandler] this.instance.use is not a function +3ms
TypeError: this.instance.use is not a function
at ExpressAdapter.use (C:\study\nestjs-practice\serverless-nestjs\node_modules\#nestjs\core\adapters\http-adapter.js:20:30)
at NestApplication.use (C:\study\nestjs-practice\serverless-nestjs\node_modules\#nestjs\core\nest-application.js:140:26)
at C:\study\nestjs-practice\serverless-nestjs\node_modules\#nestjs\core\nest-factory.js:127:40
at Function.run (C:\study\nestjs-practice\serverless-nestjs\node_modules\#nestjs\core\errors\exceptions-zone.js:9:13)
at Proxy.<anonymous> (C:\study\nestjs-practice\serverless-nestjs\node_modules\#nestjs\core\nest-factory.js:126:46)
at Proxy.<anonymous> (C:\study\nestjs-practice\serverless-nestjs\node_modules\#nestjs\core\nest-factory.js:168:54)
at bootstrapServer (C:\study\nestjs-practice\serverless-nestjs\.build\src\lambda.js:16:17)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async handler (C:\study\nestjs-practice\serverless-nestjs\.build\src\lambda.js:23:20)
at async InProcessRunner.run (C:\study\nestjs-practice\serverless-nestjs\node_modules\serverless-offline\dist\lambda\handler-runner\in-process-runner\InProcessRunner.js:211:24)
at async LambdaFunction.runHandler (C:\study\nestjs-practice\serverless-nestjs\node_modules\serverless-offline\dist\lambda\LambdaFunction.js:355:20)
at async hapiHandler (C:\study\nestjs-practice\serverless-nestjs\node_modules\serverless-offline\dist\events\http\HttpServer.js:601:18)
at async module.exports.internals.Manager.execute (C:\study\nestjs-practice\serverless-nestjs\node_modules\#hapi\hapi\lib\toolkit.js:45:28)
at async Object.internals.handler (C:\study\nestjs-practice\serverless-nestjs\node_modules\#hapi\hapi\lib\handler.js:46:20)
at async exports.execute (C:\study\nestjs-practice\serverless-nestjs\node_modules\#hapi\hapi\lib\handler.js:31:20)
at async Request._lifecycle (C:\study\nestjs-practice\serverless-nestjs\node_modules\#hapi\hapi\lib\request.js:312:32)
at async Request._execute (C:\study\nestjs-practice\serverless-nestjs\node_modules\#hapi\hapi\lib\request.js:221:9)
How can I fix it?
Except for the lambda.ts and serverless.yml files, the settings are the same as when the nest.js project was created.
I'll post the code, please let me know if you know a solution
lambda.ts
import { NestFactory } from '#nestjs/core';
import { Handler, Context } from 'aws-lambda';
import { ExpressAdapter } from '#nestjs/platform-express';
import * as express from 'express';
import { Server } from 'http';
import { AppModule } from './app.module';
import { eventContext } from 'aws-serverless-express/middleware';
import { createServer, proxy } from 'aws-serverless-express';
const binaryMimeTypes: string[] = [];
let cachedServer: Server;
async function bootstrapServer(): Promise<Server> {
if (!cachedServer) {
const expressApp = express();
const nestApp = await NestFactory.create(
AppModule,
new ExpressAdapter(express),
);
nestApp.use(eventContext);
await nestApp.init();
cachedServer = createServer(expressApp, undefined, binaryMimeTypes);
}
return cachedServer;
}
export const handler: Handler = async (event: any, context: Context) => {
cachedServer = await bootstrapServer();
return proxy(cachedServer, event, context, 'PROMISE').promise;
};
serverless.yml
service:
name: serverless-nestjs
plugins:
- serverless-plugin-typescript
- serverless-plugin-optimize
- serverless-offline
provider:
name: aws
runtime: nodejs12.x
functions:
main: # The name of the lambda function
# The module 'handler' is exported in the file 'src/lambda'
handler: src/lambda.handler
events:
- http:
method: any
path: /{any+}

Related

Why can't I mapped more api in NestJS?

To add http://localhost:8080/api/v1/admin (GET) to develop an api with NestJS, we added Get annotation and proceeded with the api development, but the api was not mapped, and if you call that api, a 404notfound error will occur.
What kind of problem?
// admin.controller.ts
import { Body, Controller, Get, HttpCode, Post, UseGuards } from '#nestjs/common';
import {
ApiTags,
ApiOperation,
ApiResponse,
} from '#nestjs/swagger';
import { ReqAdmin } from 'src/lib/decorator/req-admin.decorator';
import { HttpAuthGuard } from 'src/guards/auth/http-auth.guard';
import { BaseResponse } from 'src/models/http/base.response';
import { AdminService } from './admin.service';
import { CreateAdminDto } from './dto/create.admin.dto';
import { LoginAdminDto } from './dto/login.admin.dto';
import { Admin } from 'src/entities/admin.entity';
#Controller('admin')
#ApiTags('관리자 API')
export class AdminController {
constructor(
private readonly adminService: AdminService
) {}
#Get('/')
#UseGuards(HttpAuthGuard)
#ApiOperation({ summary: '내 정보 보기', description: '내정보 보기' })
#ApiResponse({ status: 200, description: '내 정보 조회 성공' })
public async findOne(#ReqAdmin() admin: Admin): Promise<BaseResponse> {
const data = await this.adminService.findOneById(admin.id);
return BaseResponse.object('내정보 조회 성공', {
data,
})
}
#Post('/')
#ApiOperation({ summary: '관리자 생성 API', description: '관리자를 생성한다.' })
#ApiResponse({ status: 201, description: '관리자 생성성공' })
public async create(#Body() createAdminDto: CreateAdminDto) {
await this.adminService.create(createAdminDto);
return BaseResponse.object('관리자 생성성공')
}
#Post('/login')
#HttpCode(200)
#ApiOperation({ summary: '관리자 로그인 API', description: '관리자 로그인' })
#ApiResponse({ status: 200, description: '관리자 로그인성공', type: String })
public async login(#Body() loginAdminDto: LoginAdminDto) {
const token = await this.adminService.login(loginAdminDto);
return BaseResponse.object('관리자 로그인성공', {
'x-access-token': token
})
}
}
// admin.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Admin } from 'src/entities/admin.entity';
import { TokenModule } from 'src/token/token.module';
import { TokenService } from 'src/token/token.service';
import { AdminController } from './admin.controller';
import { AdminRepository } from './admin.repository';
import { AdminService } from './admin.service';
#Module({
imports: [
TypeOrmModule.forFeature([
Admin
])
],
providers: [AdminService, TokenService],
exports: [AdminService],
controllers: [AdminController]
})
export class AdminModule {}
// terminal
iwonje#iwonje-ui-MacBookAir mcn-admin-backend % nest start
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [NestFactory] Starting Nest
application...
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [InstanceLoader] AppModule
dependencies initialized +42ms
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [InstanceLoader] TypeOrmModule
dependencies initialized +0ms
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [InstanceLoader] TypeOrmCoreModule
dependencies initialized +303ms
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [InstanceLoader] TypeOrmModule
dependencies initialized +0ms
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [InstanceLoader] AdminModule
dependencies initialized +1ms
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [RoutesResolver] AdminController
{/api/v1/admin}: +287ms
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [RouterExplorer] Mapped
{/api/v1/admin, POST} route +1ms
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [RouterExplorer] Mapped
{/api/v1/admin/login, POST} route +1ms
[Nest] 40115 - 2022. 10. 11. 오후 4:12:15 LOG [NestApplication] Nest application
successfully started +1ms
// app.module.ts
import { Module } from '#nestjs/common';
import { TypeOrmModule, TypeOrmModuleOptions } from '#nestjs/typeorm';
import { DatabaseTypes } from '../database/database.enum';
import { DatabaseFactory } from '../database/database.factory';
import { AdminModule } from 'src/admin/admin.module';
#Module({
imports: [
TypeOrmModule.forRoot(
DatabaseFactory.createDatabase(DatabaseTypes.MYSQL).options(),
),
AdminModule
],
})
export class AppModule {}
Look like you had added a prefix for your api /api/v1
You can try to call http://localhost:8080/api/v1/admin instead of http://localhost:8080/admin

NestJS - Reflect.getMetadata TypeError while running e2e tests

The error:
[Nest] 163363 - 10/03/2022, 11:59:37 AM LOG [NestFactory] Starting Nest application...
[Nest] 163363 - 10/03/2022, 11:59:37 AM ERROR [ExceptionHandler]
TypeError
at Reflect.getMetadata (/home/mszan/foo/source/node_modules/reflect-metadata/Reflect.js:354:23)
at DependenciesScanner.isInjectable (/home/mszan/foo/source/node_modules/#nestjs/core/scanner.js:302:26)
at DependenciesScanner.insertModule (/home/mszan/foo/source/node_modules/#nestjs/core/scanner.js:73:18)
at DependenciesScanner.scanForModules (/home/mszan/foo/source/node_modules/#nestjs/core/scanner.js:34:43)
at DependenciesScanner.scan (/home/mszan/foo/source/node_modules/#nestjs/core/scanner.js:27:20)
at async /home/mszan/foo/source/node_modules/#nestjs/core/nest-factory.js:95:17
at async Function.asyncRun (/home/mszan/foo/source/node_modules/#nestjs/core/errors/exceptions-zone.js:22:13)
at async NestFactoryStatic.initialize (/home/mszan/foo/source/node_modules/#nestjs/core/nest-factory.js:94:13)
at async NestFactoryStatic.create (/home/mszan/foo/source/node_modules/#nestjs/core/nest-factory.js:37:9)
● process.exit called with "1"
at DEFAULT_TEARDOWN (../../node_modules/#nestjs/core/errors/exceptions-zone.js:6:40)
at Function.asyncRun (../../node_modules/#nestjs/core/errors/exceptions-zone.js:29:13)
at async NestFactoryStatic.initialize (../../node_modules/#nestjs/core/nest-factory.js:94:13)
at async NestFactoryStatic.create (../../node_modules/#nestjs/core/nest-factory.js:37:9)
The app.e2e-spec.ts:
describe('app - e2e', () => {
let app: INestApplication;
beforeAll(async () => {
const moduleRef: TestingModule = await Test.createTestingModule({
...appModuleMetadata,
imports: appModuleMetadata.imports.map((x) => {
if (x == CommonModule) {
return CommonModuleMock;
}
return x;
}),
}).compile();
app = moduleRef.createNestApplication();
await app.init();
});
});
The CommonModule contains a provider that imports fs and path packages. When I remove these imports, the tests work.
As you can see, I tried replacing CommonModule with CommonModuleMock that does not contain mentioned imports but the tests still fail.
Nest version is 9.0.11. Jest is 29.0.3. Supertest is 6.2.4. Node is 16.17.0.
What are my options?

Serverless is unable to find the handler in nestjs

I am trying to deploy my NestJS project to AWS lambda with serverless framework, I followed official documentation
I created a file serverless.ts in src directory along with main.ts file.
When I run sls offline, it successfull runs and gives following output:
Running "serverless" from node_modules
Starting Offline at stage dev (us-east-1)
Offline [http for lambda] listening on http://localhost:3002
Function names exposed for local invocation by aws-sdk:
* main: projectName-dev-main
┌────────────────────────────────────────────────────────────────────────┐
│ │
│ ANY | http://localhost:4000/ │
│ POST | http://localhost:4000/2015-03-31/functions/main/invocations │
│ ANY | http://localhost:4000/{proxy*} │
│ POST | http://localhost:4000/2015-03-31/functions/main/invocations │
│ │
└────────────────────────────────────────────────────────────────────────┘
Server ready: http://localhost:4000 🚀
But when I open the localhost URL http://localhost:4000, I get 502 Bad gateway and
following error.
ANY / (λ: main)
✖ Unhandled exception in handler 'main'.
✖ Error: Cannot find module 'main'
Require stack:
- /home/my-PC/Desktop/projectName/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js
✖ Runtime.ImportModuleError: Error: Cannot find module 'main'
Require stack:
- /home/my-PC/Desktop/projectName/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js
at _loadUserApp (/home/my-PC/Desktop/projectName/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js:310:15)
at async module.exports.load (/home/my-PC/Desktop/projectName/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/aws-lambda-ric/UserFunction.js:341:21)
at async InProcessRunner.run (file:///home/my-PC/Desktop/projectName/node_modules/serverless-offline/src/lambda/handler-runner/in-process-runner/InProcessRunner.js:41:21)
at async MessagePort.<anonymous> (file:///home/my-PC/Desktop/projectName/node_modules/serverless-offline/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js:25:14)
Here is code:
main.ts
import { NestFactory } from '#nestjs/core';
import { ValidationPipe } from '#nestjs/common';
import { AppModule } from './app.module';
async function bootstrap() {
process.env.TZ = 'Asia/Calcutta';
const app = await NestFactory.create(AppModule);
const port = process.env.PORT || 3000;
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
await app.listen(port);
}
bootstrap();
serverless.ts
import { NestFactory } from '#nestjs/core';
import serverlessExpress from '#vendia/serverless-express';
import { Callback, Context, Handler } from 'aws-lambda';
import { AppModule } from './app.module';
let server: Handler;
async function bootstrap(): Promise<Handler> {
const app = await NestFactory.create(AppModule);
await app.init();
const expressApp = app.getHttpAdapter().getInstance();
return serverlessExpress({ app: expressApp });
}
export const handler: Handler = async (
event: any,
context: Context,
callback: Callback,
) => {
server = server ?? (await bootstrap());
return server(event, context, callback);
};
serverless.yaml
service: myProject
useDotenv: true
plugins:
- serverless-offline
# - serverless-plugin-optimize
provider:
name: aws
runtime: nodejs16.x
region: us-east-1
profile: default
memorySize: 128
stage: dev
environment:
TZ: ${env:TZ}
functions:
main:
handler: dist/main.handler
events:
- http:
method: ANY
path: /
- http:
method: ANY
path: '{proxy+}'
custom:
serverless-offline:
noPrependStageInUrl: true
httpPort: 4000

ctx.switchToHttp is not a function

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.

Loading of port number for Nest.js application from JSON module

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!

Resources