【问题标题】:How to upload file using nestjs-graphql-fastify server and how to test such feature?如何使用 nestjs-graphql-fastify 服务器上传文件以及如何测试此类功能?
【发布时间】:2022-01-17 06:10:00
【问题描述】:

我很难将 .csv 文件上传到 nestjs-graphql-fastify 服务器。尝试以下代码:

  @Mutation(() => Boolean)
  async createUsers(
    @Args({ name: 'file', type: () => GraphQLUpload })
    { createReadStream, filename }: FileUpload,
  ): Promise<boolean> {
    try {
      // backend logic . . .
    } catch {
      return false;
    }
    return true;
  }

但我在使用邮递员进行测试时得到的只是这个响应:

{
    "statusCode": 415,
    "code": "FST_ERR_CTP_INVALID_MEDIA_TYPE",
    "error": "Unsupported Media Type",
    "message": "Unsupported Media Type: multipart/form-data; boundary=--------------------------511769018912715357993837"
}

使用代码优先的方法进行开发。

更新:尝试使用 fastify-multipart 但问题仍然存在。改变的是邮递员的响应:

POST body missing, invalid Content-Type, or JSON object has no keys.

【问题讨论】:

    标签: graphql nestjs fastify


    【解决方案1】:

    在 Nestjs discord 频道上找到了一些答案。

    您必须进行以下更改:

    main.ts

    async function bootstrap() {
      const adapter = new FastifyAdapter();
      const fastify = adapter.getInstance();
    
      fastify.addContentTypeParser('multipart', (request, done) => {
        request.isMultipart = true;
        done();
      });
      fastify.addHook('preValidation', async function (request: any, reply) {
        if (!request.raw.isMultipart) {
          return;
        }
    
        request.body = await processRequest(request.raw, reply.raw);
      });
    
      const app = await NestFactory.create<NestFastifyApplication>(
        AppModule,
        adapter,
      );
    
    
      await app.listen(apiServerPort, apiServerHost);
    }
    
    bootstrap();
    

    上传.scalar.ts

    import { Scalar } from '@nestjs/graphql';
    import { GraphQLUpload } from 'graphql-upload';
    
    @Scalar('Upload')
    export class UploadGraphQLScalar {
      protected parseValue(value) {
        return GraphQLUpload.parseValue(value);
      }
    
      protected serialize(value) {
        return GraphQLUpload.serialize(value);
      }
    
      protected parseLiteral(ast) {
        return GraphQLUpload.parseLiteral(ast, ast.value);
      }
    }
    

    users.resolver.ts

      @Mutation(() => CreateUsersOutput, {name: 'createUsers'})
      async createUsers(
        @Args('input', new ValidationPipe()) input: CreateUsersInput,
        @ReqUser() reqUser: RequestUser,
      ): Promise<CreateUsersOutput> {
        return this.usersService.createUsers(input, reqUser);
      }
    

    创建-shared.input.ts

    @InputType()
    export class DataObject {
      @Field(() => UploadGraphQLScalar)
      @Exclude()
      public readonly csv?: Promise<FileUpload>;
    }
    
    @InputType()
    @ArgsType()
    export class CreateUsersInput {
      @Field(() => DataObject)
      public readonly data: DataObject;
    }
    

    另外,我想提一下,你不应该使用全局验证管道(在我的例子中,它们使文件不可读)

      // app.useGlobalPipes(new ValidationPipe({ transform: true }));
    

    【讨论】:

      【解决方案2】:

      您可以使用graphql-python/gql 尝试上传文件:

      
      from gql import Client, gql
      from gql.transport.aiohttp import AIOHTTPTransport
      
      transport = AIOHTTPTransport(url='YOUR_URL')
      
      client = Client(transport=transport)
      
      query = gql('''
        mutation($file: Upload!) {
          createUsers(file: $file)
        }
      ''')
      
      with open("YOUR_FILE_PATH", "rb") as f:
      
          params = {"file": f}
      
          result = client.execute(
              query, variable_values=params, upload_files=True
          )
      
          print(result)
      

      如果你activate logging,你可以看到客户端和后端之间交换了一些消息。

      【讨论】:

      • 感谢您的回答,但我必须坚持使用 Nestjs,因此切换到 python 不是很有帮助 rn
      • 嘿,客户端可以是Python,后端是js。如果它适用于 Python,您可以使用日志记录来查看发送的确切内容,然后与邮递员发送的数据进行比较
      猜你喜欢
      • 2020-05-09
      • 2020-12-22
      • 2019-09-14
      • 1970-01-01
      • 2021-01-07
      • 2019-09-16
      • 2019-09-24
      • 2022-01-23
      • 2020-10-28
      相关资源
      最近更新 更多