2

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 Answers0