#typescript #graphql #nestjs
#typescript #graphql #nestjs
Вопрос:
Я хочу создать мутацию, которая отправляет на сервер объект, содержащий строковые поля, и поле, содержащее массив фотографий и описаний. Вот мой inputType:
import { InputType, Field } from '@nestjs/graphql';
import {
IsString,
MinLength,
ValidateNested,
IsOptional,
IsBoolean,
IsUUID,
IsNotEmptyObject,
} from 'class-validator';
import { FileUpload } from 'graphql-upload';
import { GraphQLUpload } from 'apollo-server-express';
@InputType()
export class HouseTourInput {
@Field()
@IsString()
@MinLength(2)
title: string;
@Field()
@IsString()
@MinLength(2)
@IsOptional()
summary: string;
@Field()
@IsString()
@MinLength(2)
@IsOptional()
category: string;
@Field()
@IsBoolean()
@IsOptional()
featured: boolean;
@Field()
@IsUUID()
authorId: string;
@Field(type => [SlidesInput])
@ValidateNested({ each: true })
slides: SlidesInput[];
}
@InputType()
class SlidesInput {
@Field(() => GraphQLUpload)
@IsNotEmptyObject()
photo: FileUpload;
@Field()
@IsString()
@MinLength(2)
description: string;
}
И вот мой решатель:
@Resolver(of => HouseTour)
export class AdminResolver {
constructor(private adminService: AdminService) {}
@Mutation(returns => HouseTour)
async createHouseTour(
@Context('user') user: IMe,
@Args('input') input: HouseTourInput,
) {
console.log(input);
// More code irrelevant to this question
}
Ввод никогда не регистрируется в консоли, поскольку кажется, что код никогда не запускается после проверки. Вот журнал ошибок:
TypeError: Promise resolver undefined is not a function
at new Promise (<anonymous>)
at TransformOperationExecutor.transform (/Users/babatundeadeyemi/workspace/234homesbackend/node_modules/class-transformer/TransformOperationExecutor.js:139:32)
at TransformOperationExecutor.transform (/Users/babatundeadeyemi/workspace/234homesbackend/node_modules/class-transformer/TransformOperationExecutor.js:273:43)
at /Users/babatundeadeyemi/workspace/234homesbackend/node_modules/class-transformer/TransformOperationExecutor.js:73:40
at Array.forEach (<anonymous>)
at TransformOperationExecutor.transform (/Users/babatundeadeyemi/workspace/234homesbackend/node_modules/class-transformer/TransformOperationExecutor.js:45:19)
at TransformOperationExecutor.transform (/Users/babatundeadeyemi/workspace/234homesbackend/node_modules/class-transformer/TransformOperationExecutor.js:273:43)
at ClassTransformer.plainToClass (/Users/babatundeadeyemi/workspace/234homesbackend/node_modules/class-transformer/ClassTransformer.js:17:25)
at Object.plainToClass (/Users/babatundeadeyemi/workspace/234homesbackend/node_modules/class-transformer/index.js:29:29)
at ValidationPipe.transform (/Users/babatundeadeyemi/workspace/234homesbackend/node_modules/@nestjs/common/pipes/validation.pipe.js:42:39)
Я не знаю, что еще делать. Я погуглил и не нашел ответа.
Комментарии:
1. Проверка graphql-проблема с загрузкой нескольких файлов, которая начинается github.com/jaydenseric/graphql-upload/issues/202
2. Я уже видел эту проблему. Это не решает мою проблему. Вместо этого мне пришлось создать конечную точку REST API только для этой функции.
3. Возникла та же проблема. Это
class-validator
связано с тем, что внутренняя попытка преобразовать объект (поскольку экземпляр файла является объектом) завершается неудачей. Мне пришлось добавить@Exclude
декоратор в поле file, но вы также можете изменитьValidationPipe
параметры.
Ответ №1:
Я не уверен, в чем основная причина вашей ошибки, но я сам столкнулся с проблемой загрузки graphql, и это расстраивало.
К счастью, я столкнулся со следующей проблемой github, которая предоставила мне рабочее решение. Необходимо отключить загрузку внутреннего graphql в apollo и использовать graphql-upload
Это мои окончательные рабочие решения для загрузки нескольких изображений в NestJS GraphQL. Убедитесь, что у вас есть папка для загрузки в корне вашего проекта.
src/app.module.ts
import { GraphQLUpload, graphqlUploadExpress } from "graphql-upload"
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common"
@Module({
imports: [
GraphQLModule.forRoot({
resolvers: { Upload: GraphQLUpload }, // define the Upload Scalar
typePaths: ['./**/*.graphql'],
uploads: false, // disable built-in upload handling
}),
],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(graphqlUploadExpress()).forRoutes("graphql")
}
}
src/app.resolver.ts
import { Args, Mutation, Query, Resolver} from '@nestjs/graphql';
import { UseGuards, Inject, Post } from '@nestjs/common';
import { createWriteStream } from 'fs';
import { FileUpload, GraphQLUpload } from "graphql-upload";
@Resolver()
export class AppResolvers {
@Mutation('uploadImages')
async uploadFile(@Args('images', {type: () => GraphQLUpload}) imgs: Promise<FileUpload>[]): Promise<Promise<string>[]> {
return await Promise.all(
imgs.map(async (img: Promise<FileUpload>) : Promise<Promise<string>>=>{
const { filename, mimetype, encoding, createReadStream } = await img;
console.log("attachment:", filename, mimetype, encoding)
const stream = createReadStream();
return new Promise((resolve,reject) =>{
stream.on('end', () => {console.log("ReadStream Ended")})
.on('close', () => {console.log("ReadStream Closed")})
.on('error', (err) => {console.error("ReadStream Error",err)})
.pipe(createWriteStream(`./upload/${filename}`))
.on('end', () => {
console.log("WriteStream Ended");
resolve("end")
})
.on('close', () => {
console.log("WriteStream Closed");
resolve("close")
})
.on('error',(err) => {
console.log("WriteStream Error",err);
reject("error")
});
});
})
)
}
}
src/app.graphql
scalar Upload
type Mutation {
uploadImages(
images: [Upload]
): [String]
}