Type "AssetAccount" is an extension type, but there is no type definition for "AssetAccount" in any subgraph Apollo Federation NestJs

Viewed 25

Am updating my nest js apollo federation and am getting this error.

/Users/leonlishenga/Documents/code/omnivoltaic/nest/microservices/microservices-apigateway/node_modules/@apollo/gateway/src/supergraphManagers/IntrospectAndCompose/index.ts:118
      throw Error(
            ^
Error: A valid schema couldn't be composed. The following composition errors were found:
        [accounts-microservice] Type "Distributor" is an extension type, but there is no type definition for "Distributor" in any subgraph.
        [accounts-microservice] Type "Item" is an extension type, but there is no type definition for "Item" in any subgraph.
        [accounts-microservice] Type "AssetAccount" is an extension type, but there is no type definition for "AssetAccount" in any subgraph.
        [accounts-microservice] Type "Person" is an extension type, but there is no type definition for "Person" in any subgraph.
        [accounts-microservice] Type "CreditAccount" is an extension type, but there is no type definition for "CreditAccount" in any subgraph.
        [auth-microservice] Type "AuthenticationInstance" is an extension type, but there is no type definition for "AuthenticationInstance" in any subgraph.
        [auth-microservice] Type "Roles" is an extension type, but there is no type definition for "Roles" in any subgraph.
        [auth-microservice] Type "Distributor" is an extension type, but there is no type definition for "Distributor" in any subgraph.
        [auth-microservice] Type "Organization" is an extension type, but there is no type definition for "Organization" in any subgraph.
        [auth-microservice] Type "Servicer" is an extension type, but there is no type definition for "Servicer" in any subgraph.
        [auth-microservice] Type "Supplier" is an extension type, but there is no type definition for "Supplier" in any subgraph.
        [auth-microservice] Type "AuthenticationSubInstance" is an extension type, but there is no type definition for "AuthenticationSubInstance" in any subgraph.
        [auth-microservice] Type "SubRoles" is an extension type, but there is no type definition for "SubRoles" in any subgraph.
        [auth-microservice] Type "SubRolePermissions" is an extension type, but there is no type definition for "SubRolePermissions" in any subgraph.
        [client-microservice] Type "Supplier" is an extension type, but there is no type definition for "Supplier" in any subgraph.
        [client-microservice] Type "Roles" is an extension type, but there is no type definition for "Roles" in any subgraph.
        [client-microservice] Type "Servicer" is an extension type, but there is no type definition for "Servicer" in any subgraph.
        [client-microservice] Type "AuthenticationInstance" is an extension type, but there is no type definition for "AuthenticationInstance" in any subgraph.
        [client-microservice] Type "Organization" is an extension type, but there is no type definition for "Organization" in any subgraph.
        [client-microservice] Type "Person" is an extension type, but there is no type definition for "Person" in any subgraph.
        [client-microservice] Type "Distributor" is an extension type, but there is no type definition for "Distributor" in any subgraph.
        [client-microservice] Type "SubRoles" is an extension type, but there is no type definition for "SubRoles" in any subgraph.
        [client-microservice] Type "ItemFleet" is an extension type, but there is no type definition for "ItemFleet" in any subgraph.
        [client-microservice] Type "ItemSKU" is an extension type, but there is no type definition for "ItemSKU" in any subgraph.
        [thing-microservice] Type "ItemFleet" is an extension type, but there is no type definition for "ItemFleet" in any subgraph.
        [thing-microservice] Type "Distributor" is an extension type, but there is no type definition for "Distributor" in any subgraph.
        [thing-microservice] Type "Supplier" is an extension type, but there is no type definition for "Supplier" in any subgraph.
        [thing-microservice] Type "ItemSKU" is an extension type, but there is no type definition for "ItemSKU" in any subgraph.
        [thing-microservice] Type "Item" is an extension type, but there is no type definition for "Item" in any subgraph.
        [thing-microservice] Type "Shipment" is an extension type, but there is no type definition for "Shipment" in any subgraph.
    at IntrospectAndCompose.createSupergraphFromSubgraphList (/Users/leonlishenga/Documents/code/omnivoltaic/nest/microservices/microservices-apigateway/node_modules/@apollo/gateway/src/supergraphManagers/IntrospectAndCompose/index.ts:118:13)

This is how my schema looks for the Distributor entity class extension in the Account Microservice

import { Directive, ObjectType, Field, ID } from '@nestjs/graphql';
import { ObjectId } from 'bson';
import { AssetAccount } from 'src/account/entities/assetAccount.entity';

@ObjectType()
@Directive('@extends')
@Directive('@key(fields: "_id")')
export class Distributor {
  @Field((type) => ID)
  @Directive('@external')
  _id: ObjectId;

  @Field((type) => [AssetAccount], { name: 'assetAccount', nullable: true })
  assetAccount?: AssetAccount;
}

In the service that owns the Distributor entity it looks like this

import { Entity, EntityRepositoryType, Enum, Property } from '@mikro-orm/core';
import { Directive, Field, ObjectType } from '@nestjs/graphql';
import { ItemFleet } from '../federation/entities/itemfleet.reference';
import { ItemSKU } from '../federation/entities/itemsku.reference';
import { DistributorRepository } from '../repositories/distributor.repository';
import { Org } from './org.entity';
import * as bcrypt from 'bcryptjs';
import { ObjectId } from 'bson';
import { PERMISSIONS } from '../enums/permissions.enum';
import { AuthenticationInstance } from '../federation/entities/authentication-instance.reference';
import { Roles } from '../federation/entities/roles.reference';

// Distributor is an instantiated object class
// This resource class can be edited and used
// by different applications and services

// A distributor is a specific type of Org
// Properties of a distributor include
// products, the SKUs that this distributor can sell, and
// fleets: each fleet is a list of unique item

@ObjectType()
@Directive('@key(fields: "_id")')
@Entity({
  tableName: 'distributor',
  customRepository: () => DistributorRepository,
})
export class Distributor extends Org {
  [EntityRepositoryType]?: DistributorRepository;

  // Standard information sets of a Distributor:
  // default org type is OrgTypes.DISTRIBUTOR
  // default org contact person should be CEO

  // Distribution related information

  // itemSKU type is to be federated from the thing-microservice
  // @Field()
  public products: [ItemSKU];

  // itemFleet type is to be federated from the thing-microservice
  // @Field()
  public fleets: [ItemFleet];

  @Field((type) => AuthenticationInstance, {
    name: 'authenticationInstance',
    nullable: true,
  })
  // @ManyToOne({ mapToPk: true })
  @Property({ persist: true })
  public activeAuthenticationInstanceId!: ObjectId;

  @Field((type) => PERMISSIONS, { nullable: true })
  @Enum()
  public activeSubRolePermission: PERMISSIONS;

  @Field((type) => Roles, { name: 'role', nullable: true })
  // @ManyToOne({ mapToPk: true, nullable: true })
  @Property({ persist: true })
  public roleId?: ObjectId;

  @Property({ persist: true })
  public password: string;

  @Field({ nullable: true })
  @Property({ persist: true, nullable: true })
  public mqtt_password: string;

  @Property({ persist: true })
  public salt: string;

  public perms: any[];

  async getUserRole(): Promise<string> {
    if (this.roleId != null) {
      // console.log(this.roleId)
      // const role = await getModelForClass(Roles).findOne({ _id: this.roleId }).exec()
      return 'Trial';
    } else {
      return null;
    }
  }

  async validatePassword(password: string): Promise<boolean> {
    const hash = await bcrypt.hash(password, this.salt);
    return hash === this.password;
  }
}

The Org that it extends to looks like this

import { Embedded, Entity, Enum, OneToOne, Property } from '@mikro-orm/core';
import { Field, InterfaceType } from '@nestjs/graphql';
import { OrgTypes } from '../enums/org-types.enum';
import { Address } from './address.entity';
import { BaseEntity } from './base.entity';
import { Person } from './person.entity';

// Actor class of objects can "act". e.g. create an event, or send a message
// All actors must extend from this class to be able to act!
@InterfaceType()
@Entity({ abstract: true })
export abstract class Org extends BaseEntity {
  // This is used for certain event consequences, and for filtering
  @Field((type) => OrgTypes)
  @Enum({ items: () => OrgTypes, default: OrgTypes.DISTRIBUTOR })
  public type: OrgTypes;

  // Actor's name
  // This is inherited by all sub-classes
  @Field()
  @Property({ default: 'OVES Distributor' })
  public name: string;

  // Actor's profile
  // This is inherited by all sub-classes
  @Field({ nullable: true })
  @Property({ default: 'Standard PAYG Distribution Established in 2021' })
  public description: string;

  // Below is address of an Org embedded
  @Field((type) => Address)
  @Embedded(() => Address, { object: true })
  public orgAddress: Address;

  @Field((type) => Person, { nullable: true })
  @OneToOne({ entity: () => Person })
  public orgContactPerson: Person;

  public contactRole: string; // e.g. CEO
}

With the BaseEntity looking like this

import { Directive, Field, ID, InterfaceType } from '@nestjs/graphql';
import { Entity, PrimaryKey, Property } from '@mikro-orm/core';
import { ObjectId } from '@mikro-orm/mongodb';

@InterfaceType()
@Directive('@key(fields: "_id")')
@Entity({
  abstract: true,
})
export abstract class BaseEntity {
  @Field(() => ID)
  @PrimaryKey()
  public _id!: ObjectId;

  @Field((type) => Boolean, { nullable: true })
  @Property({ default: false })
  public deleteStatus: boolean;

  @Field({ nullable: true })
  @Property({ nullable: true })
  public deleteAt: Date;

  @Field({ nullable: true })
  @Property({ onCreate: () => new Date() })
  public createdAt: Date;

  @Field({ nullable: true })
  @Property({ onUpdate: () => new Date(), onCreate: () => new Date() })
  public updatedAt: Date;
}

The gateway for the two subgraphs looks like this

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { LoggerModule, PinoLogger } from 'nestjs-pino';
import { GatewayModule } from './gateway/gateway.module';
import { GraphQLError, GraphQLFormattedError } from 'graphql';
import { IntrospectAndCompose } from '@apollo/gateway';
import { ApolloGatewayDriverConfig, ApolloGatewayDriver } from '@nestjs/apollo';
import { GraphQLModule } from '@nestjs/graphql';

@Module({
  imports: [
    ConfigModule.forRoot(),
    LoggerModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        pinoHttp: {
          safe: true,
          // prettyPrint: configService.get<string>('NODE_ENV') !== 'production',
        },
      }),
      inject: [ConfigService],
    }),
    GatewayModule,
    GraphQLModule.forRoot<ApolloGatewayDriverConfig>({
      driver: ApolloGatewayDriver,
      server: {
        // ... Apollo server options
        cors: true,
        context: ({ req }) => ({
          authorization: req.headers.authorization,
          universe: req.headers.universe,
        }),
      },
      gateway: {
        supergraphSdl: new IntrospectAndCompose({
          subgraphs: [
            {
              name: 'thing-microservice',
              url: 'http://localhost:3101/graphql',
            },
            {
              name: 'client-microservice',
              url: 'http://localhost:3001/graphql',
            },
            {
              name: 'event-microservice',
              url: 'http://localhost:3002/graphql',
            },
            // {
            //   name: 'ecommerce-microservice',
            //   url: 'http://ecommerce-microservice-alb-1340537921.eu-central-1.elb.amazonaws.com/graphql',
            // },
            {
              name: 'auth-microservice',
              url: 'http://localhost:3010/graphql',
            },
            {
              name: 'accounts-microservice',
              url: 'http://localhost:3011/graphql',
            },
          ],
        }),
      },
    }),
  ],
})
export class AppModule {}

I have just taken a snapshot of two subgraphs i.e account-microservice and client-microservice. My question is this, what could be causing this error or issue? I can't seem to solve it.

My Package.json for the gateway looks like this

{
  "name": "microservice-apigateway",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@apollo/gateway": "2.0.5",
    "@nestjs/apollo": "10.0.17",
    "@nestjs/axios": "^0.1.0",
    "@nestjs/common": "9.0.1",
    "@nestjs/config": "^2.2.0",
    "@nestjs/core": "9.0.1",
    "@nestjs/graphql": "10.0.18",
    "@nestjs/platform-express": "9.0.1",
    "apollo-server-express": "3.9.0",
    "graphql": "16.5.0",
    "graphql-tools": "8.3.0",
    "graphql-upload": "^12.0.0",
    "nestjs-pino": "^3.1.1",
    "reflect-metadata": "0.1.13",
    "rimraf": "3.0.2",
    "rxjs": "7.5.5",
    "ts-morph": "15.1.0"
  },
  "devDependencies": {
    "@nestjs/cli": "9.0.0",
    "@nestjs/schematics": "9.0.1",
    "@nestjs/testing": "9.0.1",
    "@types/express": "4.17.13",
    "@types/jest": "28.1.4",
    "@types/node": "18.0.3",
    "@types/supertest": "2.0.12",
    "@typescript-eslint/eslint-plugin": "5.30.5",
    "@typescript-eslint/parser": "5.30.5",
    "eslint": "8.19.0",
    "eslint-config-prettier": "8.5.0",
    "eslint-plugin-prettier": "4.2.1",
    "jest": "28.1.2",
    "prettier": "2.7.1",
    "supertest": "6.2.4",
    "ts-jest": "28.0.5",
    "ts-loader": "9.3.1",
    "ts-node": "10.8.2",
    "tsconfig-paths": "4.0.0",
    "typescript": "4.7.4"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

Anyone who can help me with this I will appreciate it greatly.

0 Answers
Related