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
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 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'
})
]
}
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.
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.
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);
}
}