NestJS: Injected dependencies are undefined during cron job execution - nestjs

I cannot get the contextual reference of the MyOtherService.
Following the docs, this is my code:
#Injectable()
export class MyService {
constructor(private readonly myOtherService: MyOtherService) {}
#Cron(CronExpression.EVERY_10_SECONDS)
async test() {
this.myOtherService.someMethod() //myOtherService is undefined;
}
}

It sounds like you have a dependency using the REQUEST scope, which cannot be instantiated during CRON as there is no request to work with. Everything must be the singleton (DEFAULT) scope.

Related

nodejs with tap: Class extends value undefined is not a constructor or null

I'm pretty new to node development and have the issue mentioned in the headline. I figured out, that this is probably a circular dependency issue. But I really don't get why.
Maybe you can help?
Here is the first part of my application that works.
I have a simple abstract class like this:
export abstract class AbstractApplication {
abstract beforeStart(): void
abstract afterStart(): void
}
Then I have a second class that extends from that AbstractApplication:
export class App extends AbstractApplication {
//implement the specific methods from AbstractApplication here and do things
async startApp(): void {
//do things here
}
}
Inside this same file, I create an instance of the App class and export it into the module like this:
const app: App = new App()
module.exports = app
Then, inside another file, the server.js, I require this app and start it like this:
const app = require("./src/App")
app.startApp()
And if I run npm run start which calls node server.js everything works and the App runs.
Now I have a seperate file that contains a third class that extends from the App class like this:
export class TestSuite extends App {
async startApp(): Promise<void> {
console.log("READY")
}
}
So as you can see, I take the app class but I override the startApp function.
Inside this same file I do the same thing I did in the App file before:
const testSuite = new TestSuite()
module.exports = testSuite
Then in a last file, I'm doing this:
const testSuite = require("./TestSuite")
testSuite.startApp()
If I now change my npm start to node theOtherFileWithTestSuiteStart.js and run npm run start, everything works also fine.
Now, the last file which contains the testSuite.startApp()should contain test functions that depend on that application, just something simple as
const testSuite = require("./TestSuite")
testSuite.startApp()
test('requests the "/" route', function () {
//test something here
})
And when I run this with tap, then I get the error above: TypeError: Class extends value undefined is not a constructor or null
The interesting thing is: If I extend the TestSuite class from AbstractApplication, I at least get an error that the test is unfinished (which may be okay because of dummy implementation). If I extend it from the App class, this error occures.
Any ideas?

Connection "default" was not found - TypeORM, NestJS and external NPM Package

I'm using NestJs to create a couple of applications and I want to move the code from a NestInterceptor for an external NPM Package so I can use the same interceptor in multiple applications.
The problem is that the same code that works when used "locally" just stop working when moved to the external package.
Here's the code for the interceptor:
import { Injectable, NestInterceptor, CallHandler, ExecutionContext } from '#nestjs/common'
import { map } from 'rxjs/operators'
import { getManager } from 'typeorm'
import jwt_decode from 'jwt-decode'
#Injectable()
export class MyInterceptor implements NestInterceptor {
entity: any
constructor(entity: any) {
this.entity = entity
}
async intercept(context: ExecutionContext, next: CallHandler): Promise<any> {
const request = context.switchToHttp().getRequest()
const repository = getManager().getRepository(this.entity)
return next.handle().pipe(map((data) => data))
}
}
Here's a given controller:
import { myInterceptor } from "../src/interceptors/interceptor.ts";
#UseInterceptors(new CompanyIdInterceptor(User))
export class UserController {
}
This works fine, but if a move the file to an external NPM package and import from it like this:
import { myInterceptor } from "mynpmpackage";
I get the following error:
[Nest] 24065 - 04/18/2019, 10:04 AM [ExceptionsHandler] Connection "default" was not found. +26114ms
ConnectionNotFoundError: Connection "default" was not found.
at new ConnectionNotFoundError (/home/andre/Services/npm-sdk/src/error/ConnectionNotFoundError.ts:8:9)
at ConnectionManager.get (/home/andre/Services/npm-sdk/src/connection/ConnectionManager.ts:40:19)
Any ideas, on what causes this and how to solve it?
This might not be your problem exactly, but I had a similar problem when moving things to external packages with TypeORM. Make sure all packages from parent project are using the same version of the TypeORM package.
In my case, using yarn why typeorm showed me two different versions were being installed. One of them was used to register the entities, while the framework connected to the SQL database using another version, generating this clash.
Check your versions using yarn why [pkg-name] or if you're using NPM, try npx npm-why [pkg-name] or install globally from https://www.npmjs.com/package/npm-why.
After verifying TypeOrm versions is same in both the packages i.e- external package and consumer repository as mentioned by #Luís Brito still issue persist then issue could be-
Basically when we create an external package - TypeORM tries to get the "default" connection option, but If not found then throws an error:
ConnectionNotFoundError: Connection "default" was not found.
We can solve this issue by doing some kind of sanity check before establishing a connection - luckily we have .has() method on getConnectionManager().
import { Connection, getConnectionManager, getConnectionOptions,
createConnection, getConnection, QueryRunner } from 'typeorm';
async init() {
let connection: Connection;
let queryRunner: QueryRunner;
if (!getConnectionManager().has('default')) {
const connectionOptions = await getConnectionOptions();
connection = await createConnection(connectionOptions);
} else {
connection = getConnection();
}
queryRunner = connection.createQueryRunner();
}
Above is a quick code-snippet which was the actual root cause for this issue but If you are interested to see complete working repositories (different example) -
External NPM Package :
Git Repo : git-unit-of-work (specific file- src/providers/typeorm/typeorm-uow.ts)
Published in NPM : npm-unit-of-work
Consumer of above package : nest-typeorm-postgre (specific files- package.json, src/countries/countries.service.ts & countries.module.ts)

How to re-import module in Typescript

I'm fairly new to typescript but I think this issue is actually indirectly related to Node. Anyway, I'm trying to write a small node lib and I'm using Typescript.
I have a class, let's say:
//foo.ts
export class Foo {
constructor(options:Options = {}) { ... }
}
However using this class directly most times will not be desirable given the nature of my lib, so I'm also exporting a module
//module.ts
import { Foo } from './foo'
let instance
... // other methods
export function init(options: Options) {
instance = new Foo(options)
}
Everything works as I expect. The issue I have is to write unit tests for module.ts. I need to write several test cases, but once I call module.init(options) once, the instance will be created and as node cache modules, importing it again in my test file will still have the foo instance there. In vanilla javascript I used the proxyquire to generate other instances of the module, but it seems that it doesn't work so well with typescript... How would I "force" node to "re-import" a "clean" instance of my module?
How would I "force" node to "re-import" a "clean" instance of my module?
A simple factory method e.g. Change
//foo.ts
export class Foo {
constructor(options:Options = {}) { ... }
}
To:
//foo.ts
class Foo {
constructor(options:Options = {}) { ... }
}
export const create(options: Options): Foo {
return new Foo(options);
}

Access extended class' properties and methods with TypeScript decorators

I'm working on an experimental refactoring of my express app and chose to go with TypeScript as I prefer strong typing with any language. I saw the potential of using TypeScript's decorators as a powerful method to build a well-structured project as DRY as possible.
I'm having issues in accessing a property from a class that is extended by a class where I have the decorator set up.
example:
class BaseRouter {
app: express.Application = express;
// some other common stuff
}
function PostMethod(route: string = '/') {
return (target: BaseRouter, key: string, descriptor: PropertyDescriptor): void {
// This is where things don't work out
// descriptor.value correctly returns the RequestHandler which I can attach to express
// target.app is undefined
target.app.post(route, descriptor.value);
}
}
router.ts
#ResourceRouter() // <= this is optional, can I access all decorators inside the class from this decorator? That would also lead me to a solution
export class BlogRouter extends BaseRouter {
#GetMethod()
index(req, res) {
// req.send(...); return posts
}
#GetMethod('/:modelId')
show(req, res, next) {
// find req.params.modelId
}
#PostMethod()
createPost() {}
#DeleteMethod()
deletePost() {}
#UpdateMethod()
updatePost() {}
}
I know this is not perfect I'm just experimenting with decorators at the moment as I have successfully used them in other scenarios that works really well. Note that this is not in any way Angular 2+ related.

Parent/Child class hierachy in nodejs

child.js
class Child {
constructor(){
this.helloWorld = "Hello World";
}
run() {
}
}
export default new Child();
parent.js
import child from './child.js';
class Parent {
constructor() {
this.child = child;
}
}
export default new Parent();
index.js
import parent from './parent.js'
console.log(parent.child.helloWorld); <-- does not throws an error, displays "Hello World"
console.log(parent.child.run); <-- throws an error (Cannot read property run from undefined)
console.log(parent.child.run()); <-- throws an error (Cannot read property run from undefined)
If I do console.log(parent.child) in index.js, run does not show up, however the property helloWorld does..
How can I have the functions exposed as well? I was hoping to be able to do this to help keep my code a bit more organized, so was going to separate it out into separate classes to help minimize the amount of code in each file.
To make one thing clear from the start: The error you seem to get has nothing to do with run not appearing in the console.log output.
If your code really throws that error then that means that the value of parent.child is undefined. Hence when you call console.log(parent.child), you should see undefined, not an object. However, I don't see why you'd get that error.
Anyways, run is defined on the prototype of parent.child, not on itself. console.log most likely shows an object's own properties (the console API is not standardized, so results can vary between environments). That's normal.
Simple example to reproduce:
var foo = {
x: 42
};
var bar = Object.create(foo);
bar.y = 21;
console.log(bar, bar.x, bar.y);
// Open the browser console to see output
bar.x is accessible even though console.log doesn't show it (in Chrome at least).
Well I'm not sure if helps you to solve the problem, but whenever I want to add inheritance, I use extends and super here is an example:
Base Class:
class BaseDataModel {
constructor() {
}
getModel() {
return 'model';
}
module.exports.BaseDataModel = BaseDataModel;
Class extending Base Class:
"use strict"
// Imports
const BaseDataModel = require('../baseDataModel').BaseDataModel; // use the proper location
class UserMembershipModel extends BaseDataModel {
constructor() {
super(); // this is optional, I use this to inherit the constructors
}
getChildModel() {
return super.getModel(); // This is how you access the function from your extended class
}
module.exports.UserMembershipModel = UserMembershipModel;
Again, not sure if it solves your problem, since your actually adding a property with a Child class. My example is actually extending (or UserMembershipModel inherits from BaseDataModel).
Hope this helps you a bit.

Resources