#nestjs/graphql not working with serverless - graphql

I have a problem with #nestjs/graphql with serverless.
When i start the app normaly with the $ nest start command, it's working well without any error.
But with the $ sls offline command, it's not running and i have this error when i go to the /graphql (playground) endpoint :
offline: ANY /graphql (λ: graphql)
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [NestFactory] Starting Nest application...
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] ConfigHostModule dependencies initialized +35ms
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] ConfigModule dependencies initialized +1ms
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] JwtModule dependencies initialized +1ms
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] GraphQLModule dependencies initialized +0ms
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] GraphQLSchemaBuilderModule dependencies initialized +0ms
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] GraphQLModule dependencies initialized +1ms
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] DatabaseModule dependencies initialized +166ms
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] AuthModule dependencies initialized +2ms
[Nest] 49532 - 04/02/2022, 22:56:30 LOG [InstanceLoader] UsersModule dependencies initialized +1ms
offline: Failure: Cannot determine a GraphQL output type for the "roles". Make sure your class is decorated with an appropriate decorator.
I think the problem is located on a specific objectType who expose the User (an other objectType+Entity).
// auth.models.ts
import { User } from '#features/graphql/users/entities';
import { Field, ObjectType } from '#nestjs/graphql';
#ObjectType()
export class SignInUserModel {
#Field(() => User, { nullable: true })
user?: User;
#Field(() => String, { nullable: true })
accessToken?: string;
#Field(() => String, { nullable: true })
refreshToken?: string;
}
Because if i remove the User field from the SignInUserModel, the problem disappear ... someone have an idea of what i need to do ?
A specific decorator or something is missing for roles in my User model ?
I am totally lost haha
About my code:
// lambda.handler
import { defaultConfig } from '#config';
import { GraphQLModule } from '#features/graphql/graphql.module';
import { Logger, ValidationPipe } from '#nestjs/common';
import { NestFactory } from '#nestjs/core';
import serverlessExpress from '#vendia/serverless-express';
import { Callback, Context, Handler } from 'aws-lambda';
let server: Handler;
async function bootstrap() {
const config = defaultConfig();
const app = await NestFactory.create(GraphQLModule);
// Logger
if (config.isLoggerEnabled) app.useLogger(app.get(Logger));
// Validation
app.useGlobalPipes(new ValidationPipe());
await app.init();
const expressApp = app.getHttpAdapter().getInstance();
return serverlessExpress({ app: expressApp });
}
export const handler: Handler = async (
event: any,
context: Context,
callback: Callback,
) => {
server = server ? server : await bootstrap();
return server(event, context, callback);
};
// graphql.module.ts
import { ConfigModule, graphqlConfig } from '#config';
import { AppService } from '#features/app.service';
import { UsersModule } from '#features/graphql/users/users.module';
import { AuthModule } from '#features/_auth/auth.module';
import { Module } from '#nestjs/common';
import { GraphQLModule as NESTJSGraphQLModule } from '#nestjs/graphql';
#Module({
imports: [
ConfigModule,
AuthModule,
NESTJSGraphQLModule.forRoot({
installSubscriptionHandlers: true,
autoSchemaFile: graphqlConfig().generatedSchemaFileLocation,
sortSchema: true,
debug: graphqlConfig().isDebugEnabled,
introspection: true,
context: ({ req }) => ({ headers: req.headers }),
playground: graphqlConfig().isPlaygroundEnabled
? {
settings: { 'schema.polling.enable': false },
}
: false,
}),
UsersModule,
],
providers: [AppService],
})
export class GraphQLModule {
constructor(private readonly appService: AppService) {
if (!this.appService.checkEnv()) process.exit();
}
}
// user.entity.ts
import { UserRole } from '#features/graphql/users/users.enums';
import { Field, ObjectType } from '#nestjs/graphql';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
#ObjectType()
#Entity({ name: 'users' })
export class User {
#PrimaryGeneratedColumn('uuid')
#Field(() => String)
id: string;
#Column('text')
#Field(() => String)
firstName: string;
#Column('text')
#Field(() => String)
lastName: string;
#Column('text')
#Field(() => String)
email: string;
#Column({ type: 'enum', enum: UserRole, array: true, default: ['USER'] })
#Field(() => [UserRole])
roles: UserRole[];
...
}
// user.enums.ts
export enum UserRole {
ADMIN = 'ADMIN',
MODERATOR = 'MODERATOR',
USER = 'USER',
}
// serverless.ts
import type { AWS } from '#serverless/typescript';
import { config as dotEnvConfig } from 'dotenv';
import * as envVar from 'env-var';
import packageConfig from './package.json';
dotEnvConfig();
const serverlessConfiguration: AWS = {
service: packageConfig.name,
useDotenv: true,
frameworkVersion: '*',
plugins: {
modules: [
'serverless-plugin-optimize',
'serverless-offline',
'serverless-plugin-warmup',
],
},
custom: {
warmup: {
default: {
enabled: true,
},
},
'serverless-offline': {
noPrependStageInUrl: true,
},
},
provider: {
name: 'aws',
lambdaHashingVersion: '20201221',
runtime: 'nodejs12.x',
apiGateway: {
shouldStartNameWithService: true,
},
environment: {
/* ... my envs ... */
},
},
functions: {
graphql: {
handler: 'dist/src/features/graphql/_lambda.handler',
events: [
{
http: {
method: 'ANY',
path: '/graphql',
},
},
],
},
},
};
module.exports = serverlessConfiguration;
I am using packages :
"dependencies": {
"#nestjs/common": "^8.0.0",
"#nestjs/config": "^1.1.6",
"#nestjs/core": "^8.0.0",
"#nestjs/graphql": "^9.1.2",
"#nestjs/jwt": "^8.0.0",
"#nestjs/passport": "^8.1.0",
"#nestjs/platform-express": "^8.0.0",
"#nestjs/typeorm": "^8.0.3",
"#vendia/serverless-express": "^4.5.3",
"apollo-server-express": "^3.6.2",
"aws-lambda": "^1.0.7",
"bcryptjs": "^2.4.3",
"class-validator": "^0.13.2",
"env-var": "^7.1.1",
"graphql": "^15",
"nestjs-pino": "^2.5.0",
"passport": "^0.5.2",
"passport-local": "^1.0.0",
"pg": "^8.7.1",
"pino-http": "^6.6.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"typeorm": "^0.2.41"
},
"devDependencies": {
"#faker-js/faker": "^6.0.0-alpha.5",
"#nestjs/cli": "^8.0.0",
"#nestjs/schematics": "^8.0.0",
"#nestjs/testing": "^8.0.0",
"#serverless/typescript": "^3.0.0",
"#types/aws-lambda": "^8.10.92",
"#types/bcryptjs": "^2.4.2",
"#types/express": "^4.17.13",
"#types/jest": "27.0.2",
"#types/node": "^16.0.0",
"#types/passport-local": "^1.0.34",
"#types/supertest": "^2.0.11",
"#typescript-eslint/eslint-plugin": "^5.0.0",
"#typescript-eslint/parser": "^5.0.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.2.5",
"npm-run-all": "^4.1.5",
"prettier": "^2.3.2",
"serverless-offline": "^8.4.0",
"serverless-plugin-optimize": "^4.2.1-rc.1",
"serverless-plugin-warmup": "^6.2.0",
"source-map-support": "^0.5.20",
"supertest": "^6.2.2",
"ts-jest": "^27.1.3",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsc-alias": "^1.5.0",
"tsconfig-paths": "^3.12.0",
"typescript": "^4.3.5"
}
Thanks for your help and I hope you have a solution :)

According to this page https://docs.nestjs.com/graphql/unions-and-enums
enums need to be declared with the function registerEnumType
registerEnumType(UserRole, {
name: 'UserRole',
});

Related

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

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.

I have problem with install react using webpack

I got this message:
[webpack-cli] Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
configuration.module.rules[0] has an unknown property 'query'. These properties are valid:
object { assert?, compiler?, dependency?, descriptionData?, enforce?, exclude?, generator?, include?, issuer?, issuerLayer?, layer?, loader?, mimetype?, oneOf?, options?, parser?, realResource?, resolve?, resource?, resourceFragment?, resourceQuery?, rules?, scheme?, sideEffects?, test?, type?, use?}
-> A rule description with conditions and effects for modules.
This is what i have in the webpack.config.js file:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
path: path.join(__dirname, '/bundle'),
filename: 'index_bundle.js'
},
devServer: {
inline: true,
port: 8001
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template: './index.html'
})
]
}

NestJs Mercurius gateway Federation only get One service

I am creating a GraphQL application using NestJs, Fastify, Mercurius with federated service.
I have created two services (User, Restaurant) but when creating the gateway, it only shows the schema of one service and not two.
I tried to inverse the order and it seems that it only takes the one on the top that means when I put User URL first it only takes user schema and the same for the restaurant. Here are a declaration of the gateway and the two service:
Gateway
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { GraphQLModule } from '#nestjs/graphql';
import {
MercuriusGatewayDriver,
MercuriusGatewayDriverConfig,
} from '#nestjs/mercurius';
#Module({
imports: [
GraphQLModule.forRoot<MercuriusGatewayDriverConfig>({
driver: MercuriusGatewayDriver,
gateway: {
services: [
{
name: 'users',
url: 'http://localhost:3001/graphql',
mandatory: true,
},
{
name: 'restaurants',
url: 'http://localhost:3002/graphql',
mandatory: true,
},
],
pollingInterval: 5000,
},
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
User
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from '../user/user.module';
import { JwtModule } from '#nestjs/jwt';
import { ConfigModule, ConfigService } from '#nestjs/config';
import { AddressModule } from '../address/address.module';
import { GraphQLModule } from '#nestjs/graphql';
import {
MercuriusFederationDriver,
MercuriusFederationDriverConfig,
} from '#nestjs/mercurius';
#Module({
imports: [
GraphQLModule.forRoot<MercuriusFederationDriverConfig>({
driver: MercuriusFederationDriver,
autoSchemaFile: true,
federationMetadata: true,
}),
UserModule,
AddressModule,
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
secret: configService.get('SECRET_JWT_ACCESS_KEY'),
}),
inject: [ConfigService],
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
restaurant
import { ConfigModule, ConfigService } from '#nestjs/config';
import { JwtModule } from '#nestjs/jwt';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { RestaurantModule } from '../restaurant/restaurant.module';
import { RestauAddressModule } from '../restau-address/restau-address.module';
import { GraphQLModule } from '#nestjs/graphql';
import {
MercuriusFederationDriver,
MercuriusFederationDriverConfig,
} from '#nestjs/mercurius';
#Module({
imports: [
GraphQLModule.forRoot<MercuriusFederationDriverConfig>({
driver: MercuriusFederationDriver,
autoSchemaFile: true,
federationMetadata: true,
}),
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
secret: configService.get('SECRET_JWT_ACCESS_KEY'),
}),
inject: [ConfigService],
}),
RestaurantModule,
RestauAddressModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
all separately are working fine.

Remote schema stitching with latest versions of Apollo and GraphQL tools

i'm having a hard time figuring out the problem with my setup. I have been looking at the documentations but between apollo and graphql-tools the APIs changed frequently.
When i run this script, the console says "Error: Query root type must be provided."
import { ApolloServer } from "apollo-server";
import { loadSchema } from "#graphql-tools/load";
import { UrlLoader } from "#graphql-tools/url-loader";
import { stitchSchemas } from "#graphql-tools/stitch";
import fetch from "node-fetch";
import dotenv from "dotenv";
dotenv.config({ path: "../.env" });
async function startServer() {
const shopifySchema = await loadSchema(process.env.SHOPIFY_STOREFRONT_URL, {
loaders: [new UrlLoader()],
headers: {
"X-Shopify-Storefront-Access-Token":
process.env.SHOPIFY_STOREFRONT_API_TOKEN,
},
fetch,
});
const contentfulSchema = await loadSchema(process.env.CONTENTFUL_API_URL, {
loaders: [new UrlLoader()],
headers: {
Authorization: `Bearer ${process.env.CONTENTFUL_API_TOKEN}`,
},
fetch,
});
const gatewaySchema = stitchSchemas({
subschemas: [{ schema: shopifySchema }, { schema: contentfulSchema }],
});
const server = new ApolloServer({ schema: gatewaySchema });
return await server.listen();
}
startServer().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
These are my dependencies:
{
"#graphql-tools/load": "^7.3.2",
"#graphql-tools/schema": "^8.2.0",
"#graphql-tools/stitch": "^8.3.1",
"#graphql-tools/url-loader": "^7.2.0",
"apollo-server": "^3.4.0",
"dotenv": "^10.0.0",
"graphql": "^15.6.1",
"node-fetch": "^3.0.0"
}
Anyone knows what could be wrong with this?
Ok, i have found out that my url endpoints were just incorrect.
I'll leave the question open in case might be useful to someone.

Nativescript + angular : blank page on tab view after upgrading to 8.2.0 without any error

Environment
CLI: 6.0.3
Cross-platform modules:6.0.0
Android Runtime:6.0.2
iOS Runtime:6.0.2
Plugin(s):
NativeScript-Angular:8.2.0
Angular:8.2.0
After upgrading to the latest cli and nativescript-angular I get a blank white screen when I start the app which opens the page tab based, but when I try to output something using the component ts file I can get it on the console. The problem is only at the template level (I get a blank page).
this is my app.modules.ts file:
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { CoreModule } from "./core/core.module";
import { SharedModule } from "./shared/shared.module";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { NativeScriptCommonModule } from "nativescript-angular/common";
import { TNSImageModule } from 'nativescript-image/angular';
import * as applicationModule from "tns-core-modules/application";
import * as imageModule from "nativescript-image";
declare var GMSServices: any;
if (applicationModule.android) {
applicationModule.on(applicationModule.launchEvent, () => {
console.log('initialize pipeline');
imageModule.initialize();
});
} else {
GMSServices.provideAPIKey("*********");
}
// Uncomment and add to NgModule imports if you need to use two-way binding
// import { NativeScriptFormsModule } from "nativescript-angular/forms";
// Uncomment and add to NgModule imports if you need to use the HttpClient wrapper
// import { NativeScriptHttpClientModule } from "nativescript-angular/http-client";
#NgModule({
bootstrap: [AppComponent],
imports: [NativeScriptCommonModule, CoreModule, SharedModule, TNSImageModule, AppRoutingModule],
declarations: [AppComponent],
providers: [],
schemas: [NO_ERRORS_SCHEMA]
})
/*
Pass your application module to the bootstrapModule function located in main.ts to start your app
*/
export class AppModule {}
this is the app-routing.modules.ts
import { NgModule } from "#angular/core";
import { NativeScriptRouterModule } from "nativescript-angular/router";
//import { hasKey } from "tns-core-modules/application-settings";
import { Routes } from "#angular/router";
//const homePath = (hasKey('skipLoginScreen') ? 'home/tabs':'auth/login');
const routes: Routes = [
{
path: "",
redirectTo: "home",
pathMatch: "full"
},
{
path: "home",
loadChildren: "~/app/home/home.module#HomeModule"
},
{
path: "products",
loadChildren: "~/app/products/products.module#ProductsModule"
},
{
path: "auth",
loadChildren: "~/app/auth/auth.module#AuthModule"
},
{
path: "account",
loadChildren: "~/app/account/account.module#AccountModule"
},
{
path: "cart",
loadChildren: "~/app/cart/cart.module#CartModule"
}
];
#NgModule({
imports: [NativeScriptRouterModule.forRoot(routes, { enableTracing: true } )],
exports: [NativeScriptRouterModule]
})
export class AppRoutingModule {}
this is my home-routing.module.ts:
import { NgModule } from "#angular/core";
import { Routes } from "#angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";
import { TabsComponent } from "./tabs.component";
import { HomeComponent } from "./home-tab/home.component";
import { CategoriesComponent } from "./categories-tab/categories.component";
import { InfoComponent } from "./info-tab/info.component";
import { LocationsComponent } from "./locations-tab/locations.component";
import { AccountComponent } from "./account-tab/account.component";
export const COMPONENTS = [TabsComponent, HomeComponent, CategoriesComponent, InfoComponent, LocationsComponent, AccountComponent];
const routes: Routes = [
{
path: "",
redirectTo: "tabs",
pathMatch: "full"
},
{
path: "tabs",
component: TabsComponent,
children: [{ path: "home", component: HomeComponent, outlet: "homeTab" }, { path: "categories", component: CategoriesComponent, outlet: "categoriesTab" }, { path: "info", component: InfoComponent, outlet: "infoTab" }, { path: "locations", component: LocationsComponent, outlet: "locationsTab" }, { path: "account", component: AccountComponent, outlet: "accountTab" }]
}
];
#NgModule({
imports: [NativeScriptRouterModule.forChild(routes)],
exports: [NativeScriptRouterModule]
})
export class HomeRoutingModule {}
this is my home.module.ts:
import { NgModule, NO_ERRORS_SCHEMA } from "#angular/core";
import { HomeRoutingModule, COMPONENTS } from "./home-routing.module";
import { SharedModule } from "../shared/shared.module";
import { PushNotificationsService } from './../core/services/push-notifications.service';
// Uncomment and add to NgModule imports if you need to use two-way binding
// import { NativeScriptFormsModule } from "nativescript-angular/forms";
// Uncomment and add to NgModule imports if you need to use the HttpClient wrapper
// import { NativeScriptHttpClientModule } from "nativescript-angular/http-client";
#NgModule({
imports: [SharedModule, HomeRoutingModule],
providers: [PushNotificationsService],
declarations: [...COMPONENTS],
schemas: [NO_ERRORS_SCHEMA]
})
/*
Pass your application module to the bootstrapModule function located in main.ts to start your app
*/
export class HomeModule {}
this is my tabs.component.ts:
import { Component, OnInit } from "#angular/core";
import { Page } from "tns-core-modules/ui/page";
import { RouterExtensions } from "nativescript-angular/router";
import { DataService } from "../core/services/data.service";
import { ActivatedRoute } from "#angular/router";
#Component({
selector: "tabs",
moduleId: module.id,
templateUrl: "./tabs.component.html"
})
export class TabsComponent implements OnInit {
selectedIndex: number = 4;
constructor(private page: Page, private activeRoute: ActivatedRoute, private dataService: DataService, private routerExt: RouterExtensions) {}
ngOnInit(): void {
this.page.actionBarHidden = true;
this.routerExt.navigate([{ outlets: { homeTab: ["home"], infoTab: ["info"], categoriesTab: ["categories"], accountTab: ["account"], locationsTab: ["locations"] } }], { relativeTo: this.activeRoute });
this.dataService.getActivatedTab().subscribe(index => {
this.selectedIndex = index;
});
}
onTabChanged(args) {
setTimeout(() => {
this.dataService.setActivatedTab(args.newIndex);
}, 30);
}
}

Resources