NestJS 使用 GraphQL 上传 [关闭]
Posted
技术标签:
【中文标题】NestJS 使用 GraphQL 上传 [关闭]【英文标题】:NestJS upload using GraphQL [closed] 【发布时间】:2018-08-08 14:30:03 【问题描述】:有没有人举例说明如何使用 GraphQl 在 NestJs 中上传文件?
我可以通过控制器使用给定的示例上传
https://github.com/nestjs/nest/issues/262#issuecomment-366098589,
但我找不到任何全面的文档如何在 NestJS 中使用 GrahpQL 进行上传
【问题讨论】:
【参考方案1】:Apollo Server 2.0 现在应该可以做到这一点(封装在 Nest 中),虽然我需要安装 graphql-upload
并导入 GraphQLUpload
,因为我找不到 Upload
类型:
@Mutation(() => Image, nullable: true )
async addImage(@Args( name: 'image', type: () => GraphQLUpload ) image)
// Do stuff with image...
【讨论】:
【参考方案2】:在回答此问题时,FileInterceptor
正在使用 multer
并通过将 ExecutionContext
转换为 http
它使用 getRequest
和 getResponse
方法来提供 req
和 res
到 multer.single
它们在 GraphQL 中未定义(req
和 res
)。
我尝试使用以下方法从上下文中获取请求:
const ctx = GqlExecutionContext.create(context);
ctx
中有 req
属性,但我找不到使用 multer
的方法(还)。
无论如何,我对FileFieldsInterceptor
进行了一些更改以在我的项目中使用它,但是当我有时间清理它时,我可能会提出拉取请求:
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
...
【讨论】:
【参考方案3】:此实现与 Node >= v14 完美配合
-
package.json
如果添加了 fs-capacitor 和 graphql-upload 条目,请从解决方案部分删除它们,并安装最新版本的 graphql-upload(此时为 v11.0.0)包作为依赖项。
-
src/app.module.ts
禁用 Apollo Server 的内置上传处理并将 graphqlUploadExpress 中间件添加到您的应用程序。
import graphqlUploadExpress from "graphql-upload"
import MiddlewareConsumer, Module, NestModule from "@nestjs/common"
@Module(
imports: [
GraphQLModule.forRoot(
uploads: false, // disable built-in upload handling
),
],
)
export class AppModule implements NestModule
configure(consumer: MiddlewareConsumer)
consumer.apply(graphqlUploadExpress()).forRoutes("graphql")
-
src/blog/post.resolver.ts(示例解析器)
从 apollo-server-core 中移除 GraphQLUpload 导入,改为从 graphql-upload 导入
import FileUpload, GraphQLUpload from "graphql-upload"
@Mutation(() => Post)
async postCreate(
@Args("title") title: string,
@Args("body") body: string,
@Args("attachment", type: () => GraphQLUpload ) attachment: Promise<FileUpload>,
)
const filename, mimetype, encoding, createReadStream = await attachment
console.log("attachment:", filename, mimetype, encoding)
const stream = createReadStream()
stream.on("data", (chunk: Buffer) => /* do stuff with data here */)
来源: https://github.com/nestjs/graphql/issues/901#issuecomment-780007582
我发现其他一些有用的链接:
https://stephen-knutter.github.io/2020-02-07-nestjs-graphql-file-upload/ 用于使用邮递员上传文件Link【讨论】:
【参考方案4】:编辑:根据下面的Developia comment,apollo-server 现在实现了file upload。应该是首选方式。
以下,原答案,供参考。
通常不使用 GraphQL 进行上传。 GraphQL 是花哨的“API 规范”,这意味着最终,低级别的 HTTP 请求和响应会被转换为 JSON 对象或从 JSON 对象转换(如果您没有自定义传输)。
一种解决方案可能是在 GraphQL 架构中定义特殊端点,例如:
mutation Mutation
uploadFile(base64: String): Int
然后客户端会将二进制数据转换为 base64 字符串,这将在解析器端进行相应处理。这样,文件将成为 GraphQL 客户端和服务器之间交换的 JSON 对象的一部分。
虽然这可能适合小文件,少量操作,但绝对不是上传服务的解决方案。
【讨论】:
如果您要上传多个文件或文件很大,则使用 Base64 上传文件是不可扩展的。现在可以使用当前合并到 apollo-server@2 中的 apollo-upload-server,因此它可以处理多部分表单数据。 Nestjs 提供 apollo-graphql@2 作为 gql 服务器,OP 要求提供文档,因为尽管(逻辑上)可能在 nestjs 文档中没有样本。【参考方案5】:试试这个
import Resolver, Mutation, Args from '@nestjs/graphql';
import createWriteStream from 'fs';
import GraphQLUpload from "apollo-server-express"
@Resolver('Download')
export class DownloadResolver
@Mutation(() => Boolean)
async uploadFile(@Args(name: 'file', type: () => GraphQLUpload)
createReadStream,
filename
): Promise<boolean>
return new Promise(async (resolve, reject) =>
createReadStream()
.pipe(createWriteStream(`./uploads/$filename`))
.on('finish', () => resolve(true))
.on('error', () => reject(false))
);
【讨论】:
【参考方案6】:您可以使用 apollo-upload-server 库。在我看来,这似乎是最简单的事情。干杯
【讨论】:
这不是 OP 要求的答案。【参考方案7】:您需要定义一个上传控制器并将其添加到您的 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));
【讨论】:
这个答案没有使用 GraphQL。以上是关于NestJS 使用 GraphQL 上传 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 nestjs-graphql-fastify 服务器上传文件以及如何测试此类功能?
Nestjs graphql 上传错误:缺少 POST 正文。你忘记使用 body-parser 中间件了吗?
Nestjs - @nestjs/graphql GraphQLGatewayModule 总是返回错误请求
错误:使用 Nestjs + Graphql + Typeorm 时无法确定 GraphQL 输入类型