I would create a program (script) that launches actions when it's get run, so I'm not using routes in this program
I'm using NestJS framework (requirement).
Actually I'm trying to write my code in main.ts file and importing a service with my methods .
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
import {AppService} from './app.service'
import { TreeChildren } from 'typeorm';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
let appService: AppService; <- can't use appService methods
this.appService.
bootstrap();
My service
#Injectable()
export class AppService {
constructor(
#InjectRepository(File) private readonly fileRepository: Repository<File>,
) {}
async getTypes(): Promise<File[]> {
return await this.fileRepository.find();
}
}
I would use services to treat my operations so I sould use DI, which is not working in a non class file.
I would know how to run my operations in init time in a proper way
There are two ways to do this:
A) Lifecycle Event
Use a Lifecycle Event (similar to change detection hooks in Angular) to run code and inject the services needed for it, e.g.:
Service
export class AppService implements OnModuleInit {
onModuleInit() {
console.log(`Initialization...`);
this.doStuff();
}
}
Module
export class ApplicationModule implements OnModuleInit {
constructor(private appService: AppService) {
}
onModuleInit() {
console.log(`Initialization...`);
this.appService.doStuff();
}
}
B) Execution Context
Use the Execution Context to access any service in your main.ts:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
const appService = app.get(AppService);
}
Related
I'm working in a NestJS app, and I wish to setup AWS X-Ray on it. I'm new to NestJS, and I'm not clear on how to do this.
In an Express app, the AWS docs say you do this:
var app = express();
var AWSXRay = require('aws-xray-sdk');
app.use(AWSXRay.express.openSegment('MyApp'));
app.get('/', function (req, res) {
res.render('index');
});
app.use(AWSXRay.express.closeSegment());
But there isn't that linear flow in NestJS, so I'm not sure how AWS X-Ray would be integrated. I noticed this answer from 2 years ago (not sure if there's a better way now), but that doesn't show the middleware setup necessary, and it also doesn't show how the interceptor would integrate into the app (i.e. what will the setup be like)
ATTEMPTED SOLUTION
I created a Middleware class:
import { Injectable, NestMiddleware } from '#nestjs/common';
import { Request, Response, NextFunction } from 'express';
import AWSXRay from 'aws-xray-sdk';
#Injectable()
export class XRayMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
AWSXRay.express.openSegment('application-name');
next();
}
}
I then created an Interceptor class:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '#nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import AWSXRay from 'aws-xray-sdk';
import { HttpAdapterHost } from '#nestjs/core';
#Injectable()
export class XRayInterceptor implements NestInterceptor {
constructor(private readonly httpAdapter: HttpAdapterHost) {}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(tap(() => this.httpAdapter.httpAdapter.use(AWSXRay.express.closeSegment())));
}
}
I then updated the app.module.ts to:
import { AppConfigModule } from '#app-config/app-config.module';
import { Module, NestModule, MiddlewareConsumer, RequestMethod } from '#nestjs/common';
import { CustomersModule } from './customers/customers.module';
import { HealthModule } from './health/health.module';
import { XRayMiddleware } from './middleware/xray.middleware';
#Module({
imports: [AppConfigModule, HealthModule, CustomersModule],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(XRayMiddleware).forRoutes({ path: '*', method: RequestMethod.ALL });
}
}
And finally, I added this line to my main.ts:
const app = await NestFactory.create(AppModule);
app.useGlobalInterceptors(new XRayInterceptor(app.get(HttpAdapterHost)));
When I run the application, and hit an endpoint, I get the following error:
Thanks
The X-Ray SDK for Node.js does not support instrumenting NestJS, but OpenTelemetry JavaScript does: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-nestjs-core
You can send traces to X-Ray using OpenTelemetry by following the steps in this getting started guide: https://aws-otel.github.io/docs/getting-started/js-sdk/trace-manual-instr
In NestJS I have custom logger:
import { Injectable, Logger, Scope } from '#nestjs/common';
#Injectable({ scope: Scope.TRANSIENT })
export class LoggerService extends Logger {
log(message: any) {
super.log(message);
}
error(message: any) {
super.log(message);
}
warn(message: any) {
super.log(message);
}
debug(message: any) {
super.log(message);
}
verbose(message: any) {
super.log(message);
}
setContext(context: string) {
super.context = context;
}
}
It is registered globally:
import { Global, Module } from '#nestjs/common';
import { LoggerService } from './logger.service';
#Global()
#Module({
providers: [LoggerService],
exports: [LoggerService],
})
export class LoggerModule {}
Is there any way to somehow pass context on injection in service constructor and avoid execution of logger.setContext(context) in every service - instead just set it in LoggerService constructor?
Example usage now:
constructor(private logger: LoggerService) {
this.logger.setContext(ClassName.name);
}
Expected usage:
constructor(private logger: LoggerService) {}
When you do private logger: LoggerService, there's no chance to make that .setContext(Service.name) call.
What you could do is something like:
#Logger(Service.name) private logger: LoggerService
How? Read this article: Advanced NestJS: Dynamic Providers
I'm trying to build an API with nest.js but I'm making use of vanilla javascript instead of the popular typescript. From the nest docs, I set up typeorm but I can't implement the example code in vanilla javascript, and for some reason, the javascript example isn't available on nest js docs.
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
#Injectable()
export class UsersService {
constructor(
#InjectRepository(User)
private usersRepository: Repository<User>,
) {}
findAll(): Promise<User[]> {
return this.usersRepository.find();
}
findOne(id: string): Promise<User> {
return this.usersRepository.findOne(id);
}
async remove(id: string): Promise<void> {
await this.usersRepository.delete(id);
}
}
Any form of assistance would be much appreciated.
In the documentation, on the top right corner of the code example, generally you can click to switch between TS ans JS code example:
JS
import { Injectable, Dependencies } from '#nestjs/common';
import { getRepositoryToken } from '#nestjs/typeorm';
import { User } from './user.entity';
#Injectable()
#Dependencies(getRepositoryToken(User))
export class UsersService {
constructor(usersRepository) {
this.usersRepository = usersRepository;
}
findAll() {
return this.usersRepository.find();
}
findOne(id) {
return this.usersRepository.findOne(id);
}
async remove(id) {
await this.usersRepository.delete(id);
}
}
I made a plain typeScript class in nest.js.
JwtTokenService.js
// JwtTokenService.js
import { Injectable, Optional } from '#nestjs/common';
import { JwtService } from '#nestjs/jwt';
import { JwtPayload } from '../modules/auth/interface/jwt-payload.interface';
#Injectable()
export class JwtTokenService {
constructor(private readonly jwtService: JwtService) {}
async generateJWT(payload: object): Promise<string> {
payload['type'] = 'access_token';
const token = this.jwtService.sign({ payload });
return token;
}
}
Now how can I use this in any controller. like user, auth and other.
Register the service in the nest application module:
import { Module } from '#nestjs/common';
import { YourController } from './path-to/your.controller';
import { JwtTokenService } from './path-to/JwtTokenService.service';
#Module({
controllers: [YourController],
providers: [JwtTokenService],
})
export class ApplicationModule {}
Then you can use it in your controller:
import { Controller, Get, Post, Body } from '#nestjs/common';
import { JwtTokenService } from './path-to/JwtTokenService.service';
#Controller('your')
export class YourController {
constructor(private readonly jwtTokenService: JwtTokenService) {}
#Get()
async get() {
// use `this.jwtTokenService`
...
}
}
Nest is using the a DependencyInjection pattern to provide the service to the controller, which is why you need to declare how the service is provided in the application module.
I created a core library for my project containing some components and services. I built the library with ng-packagr. In the consuming project which references the library I built my webapp containing components provided by the library. Nothing special so far. But sometimes I want a component (coming from my lib) calling a method from a Service outside of the lib. Is this possible? Can I somehow inject a service to a component which is defined inside a library?
Cheers
I've achieved this before with something like this:
Your library's service(s) should be defined as an interface rather than as a concrete implementation (as is done in OO languages quite often). If your implementing application will only sometimes want to pass in its own version of the service then you should create a Default service in your library, and use it as so:
import { Component, NgModule, ModuleWithProviders, Type, InjectionToken, Inject, Injectable } from '#angular/core';
export interface ILibService {
aFunction(): string;
}
export const LIB_SERVICE = new InjectionToken<ILibService>('LIB_SERVICE');
export interface MyLibConfig {
myService: Type<ILibService>;
}
#Injectable()
export class DefaultLibService implements ILibService {
aFunction() {
return 'default';
}
}
#Component({
// whatever
})
export class MyLibComponent {
constructor(#Inject(LIB_SERVICE) libService: ILibService) {
console.log(libService.aFunction());
}
}
#NgModule({
declarations: [MyLibComponent],
exports: [MyLibComponent]
})
export class LibModule {
static forRoot(config?: MyLibConfig): ModuleWithProviders {
return {
ngModule: LibModule,
providers: [
{ provide: LIB_SERVICE, useClass: config && config.myService || DefaultLibService }
]
};
}
}
Then in your implementing application you have the ability to pass in the optional config via your library's forRoot method (note that forRoot should only be called once per application and at the highest level possible). Note that I've marked the config parameter as optional, so you should call forRoot even if you have no config to pass.
import { NgModule, Injectable } from '#angular/core';
import { LibModule, ILibService } from 'my-lib';
#Injectable()
export class OverridingService implements ILibService {
aFunction() {
return 'overridden!';
}
}
#NgModule({
imports: [LibModule.forRoot({ myService: OverridingService })]
})
export class ImplementingModule {
}
This was from memory as I don't have the code to hand at the moment so if it doesn't work for any reason let me know.