0
votes

I have been working on an API based on NestJS and here is a part of the code where I'm experiencing quite weird behaviour.

ISSUE: PagePartModule is NOT importing any module I add to imports (in this case ImageModule) and so I'm getting undefined when trying to inject ImageService in PagePartModule's resolver. Please see the code below:

// page-part.module.ts
@Module({
  imports: [ImageModule],
  providers: [PagePartImageResolver],
})
export class PagePartModule {}



// page-part-image.resolver.ts
@Resolver(of => PagePartImage)
export class PagePartImageResolver {

  constructor(
    private readonly imageService: ImageService
  ) {}

  @ResolveProperty('image', type => Image, { nullable: true })
  async image(@Root() pagePart: PagePart) {
    // NOTE: pagePart is filled with correct data
    // ERROR: "Cannot read property 'find' of undefined",
    // this.imageService is undefined
    return await this.imageService.find({ id: pagePart.imageId });
  }
}


// image.module.ts
@Module({
  imports: [DataloaderModule],
  providers: [ImageResolver, ImageService],
  exports: [ImageService],
})
export class ImageModule {}



// image.service.ts
@Injectable()
export class ImageService {}

Note that I'm:
1) Adding ImageService in ImageModule exports decorator
2) ImageService is decorated with @Injectable()
3) Importing the ImageModule (which provides ImageService) via imports on PagePartModule
4) Injecting ImageService via constructor in page-part-image.resolver.ts

What I have tried:
- No error is thrown by NestJS on build time; Once I query the resolvers "image" field error shows up - saying Cannot read property 'find' of undefined -> imageService is undefined: not injected.
- If I inject the ImageModule to other module everything works as expected.
- Even if I create a service which is part of the PagePartModule, and put it in the PagePartModule providers it's still not injected into the specified resolver - which is weird (but trying to import the created service to other module again works as expected). - "emitDecoratorMetadata": true exists in my tsconfig.json

I believe I'm doing everything that is needed for the injection to work. (The API has over dozen modules in which I use the same approach and it works as expected)

I would appreciate any guidance for what could be causing the problem.

"dependencies": {
    "@nestjs/common": "^6.8.3",
    "@nestjs/core": "^6.8.3",
    "@nestjs/graphql": "^6.5.3",
    "@nestjs/jwt": "^6.1.1",
    "@nestjs/passport": "^6.1.0",
    "@nestjs/platform-express": "^6.8.3",
    "@nestjs/typeorm": "^6.2.0",
    "apollo-server-express": "^2.9.6",
    "aws-sdk": "^2.551.0",
    "axios": "^0.19.0",
    "crc-32": "^1.2.0",
    "dataloader": "^1.4.0",
    "dotenv": "^8.2.0",
    "graphql": "^14.5.8",
    "graphql-tools": "^4.0.5",
    "helmet": "^3.21.1",
    "lodash": "^4.17.15",
    "nestjs-redis": "^1.2.3",
    "passport": "^0.4.0",
    "passport-jwt": "^4.0.0",
    "passport-local": "^1.0.0",
    "pg": "^7.12.1",
    "reflect-metadata": "^0.1.12",
    "rimraf": "^2.6.2",
    "rxjs": "^6.3.3",
    "type-graphql": "^0.17.5",
    "typeorm": "^0.2.19",
    "uuid": "^3.3.3"
  },
  "devDependencies": {
    "@nestjs/testing": "^6.0.0",
    "@types/express": "^4.16.0",
    "@types/jest": "^23.3.13",
    "@types/node": "^10.14.22",
    "@types/supertest": "^2.0.7",
    "axios-mock-adapter": "^1.17.0",
    "concurrently": "^4.1.0",
    "jest": "^24.9.0",
    "nodemon": "^1.19.4",
    "prettier": "^1.15.3",
    "supertest": "^3.4.1",
    "ts-jest": "24.0.2",
    "ts-loader": "^6.2.0",
    "ts-node": "8.1.0",
    "tsconfig-paths": "3.8.0",
    "tslint": "5.16.0",
    "typescript": "3.4.3",
    "wait-on": "^3.2.0",
    "webpack": "^4.41.2",
    "webpack-cli": "^3.3.9",
    "webpack-node-externals": "^1.7.2"
  },
1
From your dependency list, it looks like some of the dependencies could be out of sync. You may want to make sure that they are all at the same minor version (I think 6.8 is current)Jay McDoniel
@JayMcDoniel thanks for the tip, I've just did that, issue remains.Tom
So, usually with a ResolveProperty you have a Query or a Mutation that is called first, and this is telling GraphQL how to resolve this property of that object. It looks like there is no query being executed, but I'm not 100% sure on that. Have you verified that the property from @Root() is defined as well? Still not sure why the ImageService would be null, everything else looks correct.Jay McDoniel
Sorry, it may be a bit confusing for you since you see just the part of the code. Yes, @Root() is populated correctly (its a PagePart object with imageId which should be passed to the ImageService to get the correct image), and the field "image" (thus ResolveProperty) is resolved via other Query, eg. Article, which has PageParts of which some have "image" which should resolve to the image from the injected ImageService; ImageService is actually undefined, not null; Also it's worth mentioning that I have some of the services which are Request Scoped. (it's a multi tenant API).Tom
Hmm, that is very odd. Any chance you can share the repository? I'm wondering if there is a deeper issue that is causing the problem...Jay McDoniel

1 Answers

2
votes
// incorrectly imported decorator
import { Resolver } from 'type-graphql';  

// correctly imported decorator in NestJS
import { Resolver } from '@nestjs/graphql';