@nestjs/graphql 不适用于无服务器
@nestjs/graphql not working with serverless
我对 @nestjs/graphql 和 serverless.
有疑问
当我使用 $ nest start
命令正常启动应用程序时,它运行良好,没有任何错误。
但是使用 $ sls offline
命令,它不是 运行 并且当我转到 /graphql (游乐场)端点时出现此错误:
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.
我认为问题出在公开 User
(另一个对象类型+实体)的特定对象类型上。
// 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;
}
因为如果我从 SignInUserModel
中删除 User
字段,问题就会消失...有人知道我需要做什么吗?
我的用户模型中 roles 缺少特定的装饰器或其他东西?
我完全迷路了哈哈
关于我的代码:
// 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;
我正在使用软件包:
"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"
}
感谢您的帮助,希望您能找到解决方案:)
根据此页面 https://docs.nestjs.com/graphql/unions-and-enums
枚举需要用函数声明 registerEnumType
registerEnumType(UserRole, {
name: 'UserRole',
});
我对 @nestjs/graphql 和 serverless.
有疑问当我使用 $ nest start
命令正常启动应用程序时,它运行良好,没有任何错误。
但是使用 $ sls offline
命令,它不是 运行 并且当我转到 /graphql (游乐场)端点时出现此错误:
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.
我认为问题出在公开 User
(另一个对象类型+实体)的特定对象类型上。
// 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;
}
因为如果我从 SignInUserModel
中删除 User
字段,问题就会消失...有人知道我需要做什么吗?
我的用户模型中 roles 缺少特定的装饰器或其他东西?
我完全迷路了哈哈
关于我的代码:
// 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;
我正在使用软件包:
"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"
}
感谢您的帮助,希望您能找到解决方案:)
根据此页面 https://docs.nestjs.com/graphql/unions-and-enums
枚举需要用函数声明 registerEnumType
registerEnumType(UserRole, {
name: 'UserRole',
});