使用GraphQL上传NestJS

问题描述 投票:1回答:4

有没有人有一个如何使用GraphQl上传NestJs文件的例子?

我可以通过控制器使用给定的示例上传

https://github.com/nestjs/nest/issues/262#issuecomment-366098589

但我找不到任何全面的文档如何在NestJS中使用GrahpQL上传

node.js upload graphql nestjs
4个回答
0
投票

编辑:根据下面的Developia comment,apollo-server现在实现file upload。应该是首选方式。

下面,原始答案,供参考。

通常不使用GraphQL进行上传。 GraphQL是花哨的“API规范”,这意味着在一天结束时,低级HTTP请求和响应被转换为JSON对象/从JSON对象转换(如果您没有自定义传输)。

一种解决方案可能是在GraphQL架构中定义特殊端点,如:

mutation Mutation {
  uploadFile(base64: String): Int
}

然后客户端将二进制数据转换为base64字符串,这将在解析器端相应地处理。这样,文件将成为GraphQL客户端和服务器之间交换的JSON对象的一部分。

虽然这可能适合小文件,少量操作,但绝对不是上传服务的解决方案。


1
投票

在这个答案的时候,FileInterceptor正在使用multer并将ExecutionContext转换为http,它使用getRequestgetResponse方法为req提供resmulter.single,它们是(reqres)在GraphQL中未定义。

我试图从上下文中获取请求:

const ctx = GqlExecutionContext.create(context);

reqctx财产,但我找不到使用multer(尚)的方法。

无论如何,我对FileFieldsInterceptor进行了一些更改,以便在我的项目中使用它,但是当我有时间清理它时,我可能会提出pull请求:

import { Observable } from 'rxjs';
import {
  NestInterceptor,
  Optional,
  ExecutionContext,
  mixin,
} from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { storeFile } from './storeFile';

interface IField {
  name: string;
  options?: any;
}

export function GraphqlFileFieldsInterceptor(
  uploadFields: IField[],
  localOptions?: any,
) {
  class MixinInterceptor implements NestInterceptor {
    options: any = {};
    constructor(@Optional() options: any = {}) {
      this.options = { ...options, ...localOptions };
    }

    async intercept(
      context: ExecutionContext,
      call$: Observable<any>,
    ): Promise<Observable<any>> {
      const ctx = GqlExecutionContext.create(context);
      const args = ctx.getArgs();

      let storeFilesResult = await Promise.all(
        uploadFields.map(uploadField => {
          const file = args[uploadField.name];
          return storeFile(file, {
            ...uploadField.options,
            ...this.options,
          }).then(address => {
            args[uploadField.name] = address;
            return address;
          });
        }),
      );

      return call$;
    }
  }
  const Interceptor = mixin(MixinInterceptor);
  return Interceptor;
}

和存储文件是这样的(可能不会像这样使用):

import uuid from 'uuid/v4';
import fs from 'fs';
import path from 'path';

const dir = './files';
if (!fs.existsSync(dir)) {
  fs.mkdirSync(dir);
}

export const storeFile = async (file, options): Promise<any> => {
  // options is not doing anything right now
  const { stream } = await file;
  const filename = uuid();

  const fileAddress = path.join(dir, filename + '.jpg');
  return new Promise((resolve, reject) =>
    stream
      .on('error', error => {
        if (stream.truncated)
          // Delete the truncated file
          fs.unlinkSync(fileAddress);
        reject(error);
      })
      .pipe(fs.createWriteStream(fileAddress))
      .on('error', error => reject(error))
      .on('finish', () => resolve(fileAddress)),
  );
};

在我的Cats.resolvers.ts

...
  @Mutation()
  @UseInterceptors(
    GraphqlFileFieldsInterceptor([
      { name: 'catImage1' },
      { name: 'catImage2' },
      { name: 'catImage3' },
    ]),
  )
  async cats(
    @Args('catImage1') catImage1: string,
    @Args('catImage2') catImage2: string,
    @Args('catImage3') catImage3: string,
  ){
    console.log(catImage1) // will print catImage1 address
    ...

0
投票

你可以使用apollo-upload-server lib。在我看来,这似乎是最简单的事情。干杯


0
投票

您需要定义一个上传控制器并将其添加到您的app.module中,这是一个控制器应该是什么(后端)的示例:

@Controller()
export class Uploader {
  @Post('sampleName')
  @UseInterceptors(FileInterceptor('file'))
  uploadFile(@UploadedFile() file) {
  // file name selection 
    const path = `desired path`;
    const writeStream = fs.createWriteStream(path);  
    writeStream.write(file.buffer);
    writeStream.end();
    return {
      result: [res],
    };
  }
}

并通过前端fetch调用您的控制器:

    fetch('controller address', {
          method: 'POST',
          body: data,
        })
          .then((response) => response.json())
          .then((success) => {
            // What to do when succeed 
});
          })
          .catch((error) => console.log('Error in uploading file: ', error));
© www.soinside.com 2019 - 2024. All rights reserved.