如何使用 nestjs-graphql-fastify 服务器上传文件以及如何测试此类功能?

Posted

技术标签:

【中文标题】如何使用 nestjs-graphql-fastify 服务器上传文件以及如何测试此类功能?【英文标题】:How to upload file using nestjs-graphql-fastify server and how to test such feature? 【发布时间】: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.

【问题讨论】:

【参考方案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,您可以使用日志记录来查看发送的确切内容,然后与邮递员发送的数据进行比较

以上是关于如何使用 nestjs-graphql-fastify 服务器上传文件以及如何测试此类功能?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?

WSARecv 如何使用 lpOverlapped?如何手动发出事件信号?