Inversify - Nodejs- Container binding results in max call size exceeded - node.js

I am trying to use inversify for DI injection in a small project in typescript. I wanted to create a logging middleware that logs every request with a pino logger customized. I did establish the dependencies manually when the app is created but was wooed by inversify and wanted to try it out.
But I am stuck and unable to proceed. THis is the error that I am facing. Not sure what is making the call to exceed the stack size. Please help me out
public set app_port(app_port: number) {
^
RangeError: Maximum call stack size exceeded
PinoLoggingService.ts
import * as pino from 'pino';
import * as os from 'os';
import * as momentTimeZone from 'moment-timezone';
import { DEFAULT_TIMEZONE, DEFAULT_TIME_FORMAT } from '../../shared/constants/app.constants';
import { AppConfigModel } from './../../shared/model/app.config.model';
import { isNullOrUndefined } from 'util';
import httpContext = require('express-http-context');
import { injectable, inject } from 'inversify';
import { TYPES } from '../../shared/constants/app.types';
import { AppConfigService } from '../../shared/service/app.config.service';
#injectable()
export class PinoLoggingService {
private appConfig: AppConfigModel;
constructor(#inject(TYPES.AppConfigService) private appConfigService: AppConfigService){
this.appConfig = appConfigService.appConfigModel;
}
private getTimeStamp(){
return momentTimeZone().tz(DEFAULT_TIMEZONE).format(DEFAULT_TIME_FORMAT);
}
public infoLogService (fileName): pino.Logger {
return pino({
level: 'info',
name: this.appConfig.app_name,
messageKey: 'feedback-Logs',
base: {pid: process.pid, hostname: os.hostname,
timestamp: this.getTimeStamp(),
appName: this.appConfig.app_name,
fileName: fileName,
request_id: isNullOrUndefined(httpContext.get('reqId')) ? 'Not an actual request ' : httpContext.get('reqId')
},
enabled: true,
useLevelLabels: true,
});
}
}
my AppConfigService.ts - AppConfigModel is just a plain ts with getters and setters.
#injectable()
export class AppConfigService implements IAppConfigService{
private appModel: AppConfigModel;
constructor() {
console.log('parg is:'+path.resolve(__dirname));
}
public get appConfigModel(): AppConfigModel {
if(isNullOrUndefined(this.appModel)) {
this.appModel = new AppConfigModel();
this.appModel.app_port = isNullOrUndefined(process.env.PORT) ? DEFAULT_PORT : parseInt(process.env.PORT);
this.appModel.app_lcp = process.env.LCP;
this.appModel.app_name = process.env.APP_NAME;
this.appModel.app_host = process.env.HOST;
this.appModel.app_node_env = process.env.NODE_ENV;
this.appModel.app_logging = JSON.parse (process.env.PINO_ENABLE_LOGGING);
this.appModel.app_version = process.env.VERSION;
this.appModel.app_context_path = process.env.CONTEXT_PATH;
}
return this.appModel;;
}
}
This is my loggingMiddleware.ts
import * as express from 'express';
import { AppUtilService } from './../util/app.util.service';
import { file } from '#babel/types';
import { inject, injectable } from 'inversify';
import { TYPES } from '../constants/app.types';
import { PinoLoggingService } from '../../logging/service/logging.service';
interface ILoggingMiddleware {
loggingMiddlewareMethod () : express.Router;
}
#injectable()
export class LoggingMiddleware implements ILoggingMiddleware {
constructor(#inject(TYPES.AppUtilService) private utilService: AppUtilService,
#inject(TYPES.PinoLoggingService) private pinoLoggingService: PinoLoggingService){
}
public loggingMiddlewareMethod() {
const appRouter = express.Router();
return appRouter.use((req:express.Request, res:express.Response, next) => {
const fileName = this.utilService.getFileName(__filename);
this.pinoLoggingService.infoLogService(fileName).info('req.url:', req.url);
this.pinoLoggingService.infoLogService(fileName).info('req.headers:', req.headers);
this.pinoLoggingService.infoLogService(fileName).info('req.body:', req.body);
next();
});
}
}
THis is my request tracing middleware
const httpContext = require('express-http-context');
import * as express from 'express';
import { injectable } from 'inversify';
#injectable()
export class RequestTracerMiddleware {
public requestTracer() {
const app = express();
app.use(httpContext.middleware);
}
}
THis is my inversify config
import { Container } from "inversify";
import { TYPES } from "./module/shared/constants/app.types";
import { AppConfigService } from "./module/shared/service/app.config.service";
import { AppUtilService } from "./module/shared/util/app.util.service";
import { LoggingMiddleware } from "./module/shared/middlewares/logging.middleware";
import { CommonMiddleware } from "./module/shared/middlewares/common.middlewares";
import { RequestTracerMiddleware } from "./module/shared/middlewares/request.tracer.middleware";
import { PinoLoggingService } from "./module/logging/service/logging.service";
import { StudentController } from "./module/shared/test.controller";
const DIContainer = new Container({defaultScope: "Singleton"});
DIContainer.bind<AppConfigService>(TYPES.AppConfigService).to(AppConfigService);
DIContainer.bind<AppUtilService>(TYPES.AppUtilService).to(AppUtilService);
DIContainer.bind<LoggingMiddleware>(TYPES.LoggingMiddleware).to(LoggingMiddleware);
DIContainer.bind<CommonMiddleware>(TYPES.CommonMiddleware).to(CommonMiddleware);
DIContainer.bind<RequestTracerMiddleware>(TYPES.RequestTracerMiddleware).to(RequestTracerMiddleware);
DIContainer.bind<PinoLoggingService>(TYPES.PinoLoggingService).to(PinoLoggingService);
DIContainer.bind<StudentController>(TYPES.StudentController).to(StudentController);
export default DIContainer;
This is my server.ts
import 'reflect-metadata';
import * as DIContainer from './inversify.config';
import {InversifyExpressServer } from 'inversify-express-utils'
import { inject } from 'inversify';
import { TYPES } from './module/shared/constants/app.types';
import { CommonMiddleware } from './module/shared/middlewares/common.middlewares';
import { LoggingMiddleware } from './module/shared/middlewares/logging.middleware';
import { RequestTracerMiddleware } from './module/shared/middlewares/request.tracer.middleware';
const container = DIContainer.default;
let server = new InversifyExpressServer(container);
const commMiddleware = container.resolve(CommonMiddleware);
// const requestTracingMiddleware = container.resolve(RequestTracerMiddleware);
const loggingMiddleware = container.resolve(LoggingMiddleware);
server.setConfig(appRouter => {
appRouter.use(commMiddleware.enableBodyParser());
appRouter.use(loggingMiddleware.loggingMiddlewareMethod());
});
// set errorConfig if needed
const app = server.build();
app.listen(2000, () => {
console.log('listening to port');
});
This is a sample controller that I setup.
import {controller, httpGet, httpPost, requestHeaders, requestParam, BaseHttpController, HttpResponseMessage, StringContent} from 'inversify-express-utils';
#controller("/IStudentController")
export class StudentController extends BaseHttpController {
constructor( ) {
super();
console.log('value of stdservuce:');
}
#httpGet("/Iget")
public getStudentDetails(#requestHeaders() reqHeaders: string[] ) {
// sample returning json resuilt - IHttpAcctionResults
const val = 43;
console.log('val from the servuc:', val);
return this.json(val, 200);
}
}

Related

why fresh-tabula-js not working with nestJs?

Getting errors while using fresh-tabula-js with nestJs.
Express server
import Tabula from "fresh-tabula-js";
const table = new Tabula("t5.pdf", { spreadsheet: true });
console.log(table.extractCsv().output);
NestJS
1) code-1
import { Injectable } from '#nestjs/common';
import Tabula = require('fresh-tabula-js');
#Injectable()
export class PdfExtractorService {
tabula: Tabula;
constructor() {
this.tabula = new Tabula('t5.pdf', { spreadsheet: true });
}
extractPdfToJson() {
const data: Promise<{ output: string; error: string }> =
this.tabula.getData();
console.log(data);
}
}
Error:
this.tabula.getData is not a function
2) code-2
import { Injectable } from '#nestjs/common';
import Tabula = require('fresh-tabula-js');
#Injectable()
export class PdfExtractorService {
tabula: Tabula;
constructor() {
this.tabula = new Tabula('t5.pdf', { spreadsheet: true });
}
extractPdfToJson() {
const data: Promise<{ output: string; error: string }> =
this.tabula.extractCsv().output;
console.log(data);
}
}
Error:
error TS2339: Property 'extractCsv' does not exist on type 'Tabula'.
this.tabula.extractCsv().output;
Tried all possible ways but it is not working with nestJs however it is working with expressJs.
How to make it run in nestJS?

Error injecting dependency into controller with tsyringe

I am using express and tsyringe for dependency injections.
When I try to use the service dependency on my controller I get an error UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'addressService' of undefined in file addressController.ts
I've searched for several videos and articles and I couldn't find a way to solve them. I will leave my code below
addressRepository.ts
import { AddressResponseDTO } from '../../dtos/response/address/addressResponseDTO';
export interface IAddressRepository {
getAddresses(): Array<AddressResponseDTO>;
}
addressRepositoryImpl.ts
import { AddressResponseDTO } from '../../dtos/response/address/addressResponseDTO';
import { IAddressRepository } from '../declarations/addressRepository';
export default class AddressRepositoryImpl implements IAddressRepository {
getAddresses(): Array<AddressResponseDTO> {
const address1: AddressResponseDTO = {
id: 'ADR123',
postalCode: '17014273',
address: 'Rua José Aiello',
district: 'Centro',
number: '347',
city: 'Bauru',
state: 'São Paulo',
phoneNumber: '16997102842',
clientName: 'João Mário Marcelo Campos',
};
const address2: AddressResponseDTO = {
id: 'ADR456',
postalCode: '07135290',
address: 'Rua Mariano Moya Peramos',
district: 'Jardim Adriana',
number: '1103',
city: 'Guarulhos',
state: 'São Paulo',
phoneNumber: '16997102842',
clientName: 'João Mário Marcelo Campos',
};
return [address1, address2];
}
}
addressService.ts
import { AddressResponseDTO } from '../../dtos/response/address/addressResponseDTO';
import ResultResponseDTO from '../../dtos/response/resultResponseDTO';
export interface IAddressService {
getAddresses(): ResultResponseDTO<Array<AddressResponseDTO>>;
}
addressServiceImpl.ts
import { StatusCodes } from 'http-status-codes';
import { inject, injectable } from 'tsyringe';
import logger from '../../configurations/logger';
import { AddressResponseDTO } from '../../dtos/response/address/addressResponseDTO';
import ResultResponseDTO from '../../dtos/response/resultResponseDTO';
import { IAddressRepository } from '../../repositories/declarations/addressRepository';
import { IAddressService } from '../declarations/addressService';
#injectable()
export default class AddressServiceImpl implements IAddressService {
private addressRepository: IAddressRepository;
constructor(#inject('AddressRepository') addressRepository: IAddressRepository) {
this.addressRepository = addressRepository;
}
getAddresses(): ResultResponseDTO<AddressResponseDTO[]> {
try {
logger.info('AddressService.getAddresses - start');
const addresses = this.addressRepository.getAddresses();
logger.info('AddressService.getAddresses - end');
return ResultResponseDTO.ok(StatusCodes.OK, '', addresses);
} catch (error) {
logger.error(`AddressService.getAddresses - error - message ${error}`);
return ResultResponseDTO.fail(
StatusCodes.INTERNAL_SERVER_ERROR,
'Error getting addresses',
error,
);
}
}
}
addressController.ts
Error at line: const result = this.addressService.getAddresses();
import { Request, Response } from 'express';
import { inject, injectable } from 'tsyringe';
import { IAddressService } from '../services/declarations/addressService';
#injectable()
export class AddressController {
constructor(#inject('AddressService') private addressService: IAddressService) {}
public async getAddresses(request: Request, response: Response): Promise<Response> {
const result = this.addressService.getAddresses();
return response.status(result.httpStatus).json(result.getResponse());
}
}
routes.ts
import { Router } from 'express';
import { container } from 'tsyringe';
import { AddressController } from './controllers/addressController';
import AddressRepositoryImpl from './repositories/implementations/addressRepositoryImpl';
import AddressServiceImpl from './services/implementations/addressServiceImpl';
const routes = Router();
container
.register('AddressRepository', {
useClass: AddressRepositoryImpl,
})
.resolve(AddressRepositoryImpl);
container
.register('AddressService', {
useClass: AddressServiceImpl,
})
.resolve(AddressServiceImpl);
const addressController = container.resolve(AddressController);
routes.get('/', (request, response) => {
response.send('It works!');
});
// AddressController
routes.route('/v1/address').get(addressController.getAddresses);
export default routes;
You register service inside IoC as 'AddressServiceImpl' and after that try to call to it as 'AddressService'.
// service file
#injectable()
export default class AddressServiceImpl implements IAddressService {
...
// controller file
#injectable()
export class AddressController {
constructor(#inject('AddressService') private addressService: IAddressService) {}

NestJS serving JSON and adds a "default" section repeating the JSON

I have a strange behaviour on an endpoint in NestJS serving a piece of JSON.
The JS with the JSON object is exporting
module.exports = Object.freeze({
translation: {
TestMessage: 'Bienvenue à React et react-i18next'
}
});
The result on the Client is:
{
"translation": {
"TestMessage": "Bienvenue à React et react-i18next"
},
"default": {
"translation": {
"TestMessage": "Bienvenue à React et react-i18next"
}
}
}
The question is where is the "default" coming from?
To paint the whole picture, below the module, controller and service:
Module
import { Module } from '#nestjs/common';
import { LoggerService } from '#modules/logger';
import { I18nController } from './i18n.controller';
import { I18nService } from './i18n.service';
#Module({
controllers: [I18nController],
providers: [I18nService, LoggerService],
exports: [I18nService]
})
export class I18nModule {}
Controller
import { Controller, Get, Param } from '#nestjs/common';
import { LoggerService } from '#modules/logger';
import { I18nService } from './i18n.service';
#Controller('i18n')
export class I18nController {
constructor(private logger: LoggerService, private i18nService: I18nService) {
this.logger.setContext(I18nController.name);
}
#Get('/:lang')
async getLanguage(#Param('lang') lang: string) {
console.log(lang);
return await this.i18nService.findOneByLanguageCode(lang);
}
}
Service
import { Injectable } from '#nestjs/common';
import { access } from 'fs/promises';
import { constants as fsconstants } from 'fs';
#Injectable()
export class I18nService {
async findOneByLanguageCode(language: string): Promise<any | null> {
const languagefile = __dirname + '/../../public/languages/' + language + '.js';
await access(languagefile, fsconstants.R_OK);
return await import(languagefile);
}
}
From the Client I do a simple http://localhost:3001/i18n/fr-FR
and get the above result.
Again, where is the 'default' section coming from?
There should be esModuleInterop enabled in your tsconfig.json
https://www.typescriptlang.org/tsconfig#esModuleInterop
a default import like import moment from "moment" acts the same as const moment = require("moment").default
That's why you have default object exist.
tsconfig.json
{
"compilerOptions": {
"esModuleInterop": true, // change it to false or remove it
}
}

How can i asynchronouslycall this service function in another component? Angular 11

I have an async function getIdentByInfo and in the console i get the right output if i log it in this function. As soon as i call it in another component it doesnt work and i only get 'undefined'. I know it has something to do with beeing ssynchrone and Promises but i cant figure out how to solve my issue. I need the Model class filled with attributes coming from the http request in another component to send them to another service
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IdentModel } from "../models/identmodel.model";
import { IdentteilComponent } from "../pages/identteil/identteil.component";
#Injectable({
providedIn: 'root',
})
export class InfoWebservice {
url = 'http://localhost:4201';
ident: IdentModel[];
constructor(private http: HttpClient) { }
// promise vom typ IdentModel zurückgeben
getIdentByInfo(id: string, vwk: string) {
this.http.get(this.url).toPromise().then(data => {
for (let i in data){
this.ident.push(data[i])
if ( this.ident[i].identNr == id && this.ident[i].vwk == vwk){
return this.ident[i];
}
}
});
}
}
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { InfoWebservice } from '../../webservices/info.webservice'
import { ImageWebservice } from '../../webservices/image.webservice'
import { IdentModel } from "../../models/identmodel.model";
#Component({
selector: 'app-identteil',
templateUrl: './identteil.component.html',
styleUrls: ['./identteil.component.scss']
})
export class IdentteilComponent implements OnInit {
ident = [];
identNr:string;
vwk:string;
imgFrontLink:string;
imgBackLink:string;
constructor(private router: Router, private service: InfoWebservice, private image: ImageWebservice) { }
getIdentNr() : string {
var split = this.router.url.split("/");
this.identNr = split[2];
return this.identNr;
}
//return type is STRING
getVwk() {
// output von window.location.host = repapp-maw.dbl.de
// var splitHost = window.location.host.split(".");
var splitHost = 'repapp-maw';
var splitV = splitHost.split("-");
this.vwk = splitV[1];
return this.vwk;
}
callInfoService = async () => {
return await this.service.getIdentByInfo(this.getIdentNr(), this.getVwk());
}
ngOnInit() {
console.log(this.callInfoService());
}
}
When you use angular, its always preferred not to use await/Promise. Angular has an in-built RX-JS library which has tonnes of super-awesome functionalities that you can use.
For Example, in your case, you can do something like this:
// Your Service File can make use of 'Behavior Subject'
// Please read more about it here: https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IdentModel } from "../models/identmodel.model";
import { IdentteilComponent } from "../pages/identteil/identteil.component";
#Injectable({
providedIn: 'root',
})
export class InfoWebservice {
url = 'http://localhost:4201';
ident: IdentModel[];
initialIdentValues: IdentModel = [];
private identSource: BehaviorSubject<IdentModel[]> = new BehaviorSubject<IdentModel[]>(this.initialIdentValues);
public identValuesObs$: Observable<IdentModel[]> = this.identSource.asObservable();
// Create a method to set the values in component-1
setIdentValues(identValues: IdentModel[]) {
this.identSource.next(identValues);
}
// Create a method to return values in component-2 or any component
returnIdentValues() {
return this.identValuesObs$;
}
constructor(private http: HttpClient) { }
// Change your service call to this:
getIdentByInfo(id: string, vwk: string): Observable<any> {
return this.http.get(this.url);
}
}
Now in your component-1 where you want to set the values of this identvalues:
// Component-1
constructor(private infoWebService: InfoWebService){}
// Create a method where you get the values
someMethod() {
// Call the API method here and subscribe and then set the values
this.infoWebService.getIdentInfoById(id, vwk).subscribe((data: any) => {
// Your logic goes here ANDD
if (data) {
for (let i in data){
this.ident.push(data[i])
let localIdentsWithRequiredLogic = [];
if ( this.ident[i].identNr == id && this.ident[i].vwk == vwk){
localIdentsWithRequiredLogic.push(this.ident[i]);
}
// THIS IS IMPORTANT
this.infoWebService.setIdentValues(localIdentsWithRequiredLogic);
}
}
})
}
Then in component-2 or whatever component you want, you can retrieve it using the returnIdentValues method like this:
// In component-2
inSomeMethodWhereYouRequireIdentValues() {
this.infoWebService.returnIdentValues().subscribe(data => {
console.log(data) // this is data that you set in component one
})
}

How can i fix .take() operator and preserve snapshot || Angular , Ionic 3

I have a problem in .take() operator after they change to AngulaFireObject
and preserveSnapshot.
What can be the problem?
import { Injectable } from '#angular/core';
import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';
import { User } from 'firebase/app';
import { Profile } from '../../models/profile/profile.interface';
import { Observable } from 'rxjs/observable';
import { take } from 'rxjs/operator/take';
#Injectable()
export class DataService {
profileObject : AngularFireObject<Profile>
constructor(private database: AngularFireDatabase) {
}
getProfile(user: User) {
this.profileObject = this.database.object(`/profiles/${user.uid}`, { preserveSnapshot: true }); <<<in here
return this.profileObject.take(1); <<<< and here
}
async saveProfile(user: User, profile: Profile) {
this.profileObject = this.database.object(`/profiles/${user.uid}`);
When I run my app with ionic serve it gives me this
Typescript Error Expected 1 arguments, but got 2. C:/Users/A7MD/Desktop/WallPapa/src/providers/data/data.service.ts getProfile(user: User) { this.profileObject = this.database.object(/profiles/${user.uid}, { preserveSnapshot: true }); –
and
Typescript Error Property 'take' does not exist on type 'AngularFireObject<Profile>'. C:/Users/A7MD/Desktop/WallPapa/src/providers/data/data.service.ts return this.profileObject.take(1); }
You can see the photo here:

Resources