如何使用Apollo / Graphene管理GraphQL突变中的文件上传

曾瀚昂
2023-12-01

by Lucas McGartland

卢卡斯·麦加兰(Lucas McGartland)

如何使用Apollo / Graphene管理GraphQL突变中的文件上传 (How to manage file uploads in GraphQL mutations using Apollo/Graphene)

GraphQL is an amazing way to query and manipulate data. You describe your data, ask for what you want, and get predictable results. The problem is, GraphQL only handles serializable data out of the box—there’s no way to upload files directly as part of your mutations.

GraphQL是一种查询和处理数据的绝佳方法。 您描述您的数据,询问您想要什么,并获得可预测的结果。 问题是,GraphQL仅处理开箱即用的可序列化数据,无法作为突变的一部分直接上传文件。

But what if there were a way to combine the power of GraphQL with the ease of uploading files in a multi-part request? @jaydenseric has come up with a solution: graphql-multipart-request-spec

但是,如果有一种方法可以将GraphQL的功能与在多部分请求中轻松上传文件相结合? @jaydenseric提出了一个解决方案: graphql-multipart-request-spec

If you just want the code to make this work, jump to the end of this article to find JavaScript and Python implementations of the spec for Apollo and Graphene.
如果您只是想让代码完成这项工作,请跳到本文结尾,以找到Apollo和Graphene规范JavaScript和Python实现。

使用GraphQL处理文件上传而没有分段上传(旧方法) (Handling File Uploads With GraphQL without Multipart Uploads (The Old Way))

Vanilla GraphQL doesn’t support throwing raw files into your mutations. The data you can request and manipulate is limited to what you can serialize over the network. In practice, this looks like basic types: numbers, booleans, and strings. These work great—you can build almost everything you need with basic data types.

Vanilla GraphQL不支持将原始文件放入突变中。 您可以请求和处理的数据仅限于可以通过网络序列化的数据。 实际上,这看起来像基本类型: 数字,布尔值和字符串 。 这些功能非常好-您可以使用基本数据类型构建几乎所有您需要的东西。

But what if you need to run a mutation that takes a file as an argument? For example: uploading a new profile picture. Here’s how you could deal with the problem with ordinary GraphQL:

但是,如果您需要运行一个以文件作为参数的突变,该怎么办? 例如:上传新的个人资料图片。 这是使用普通GraphQL处理问题的方法:

选项1:Base64编码 (Option 1: Base64 Encoding)

Base64 encode the image and send it over the wire as a string in your mutation. This has several disadvatanges:

Base64对图像进行编码,然后将其作为字符串发送给您的突变。 这有几个缺点:

  1. A base64 encoded file will be approximately 33% larger than the original binary.

    base64编码的文件将比原始二进制文件大33%。
  2. It’s more expensive operationally to encode and decode the file.

    编码和解码文件的操作成本更高。
  3. Complex to remember to encode and decode properly.

    记住正确编码和解码比较复杂。

选项2:单独的上传请求 (Option 2: Seperate Upload Requests)

Run a seperate server (or API) for uploading files. Upload the file in the first request, and then pass the resulting storage URL as part of your mutation (the second request).

运行单独的服务器(或API)以上传文件。 在第一个请求中上传文件,然后将生成的存储URL作为您的更改的一部分(第二个请求)传递。

However if you have to upload several files, you would have to wait until all the uploads are done before you could pass the URLs (to identify them) in your mutation, forcing a synchronous and slow process. It also adds another layer of complexity to make it handle all these requests separately in your client.

但是,如果必须上载多个文件,则必须等到所有上载完成后,才能在突变中传递URL(以识别它们),从而强制执行同步且缓慢的过程。 它还增加了另一层复杂性,使其可以在客户端中分别处理所有这些请求。

  1. It’s not asynchronous.

    它不是异步的。
  2. It’s complex to manage the other upload server.

    管理其他上传服务器非常复杂。
Wouldn’t it be cool to just pass a file in as part of the mutation parameters?
仅将文件作为突变参数的一部分传递会很酷吗?

输入分段请求规范(新方法) (Enter the Multipart Request Spec (The New Way))

This is where the multipart request spec comes in. This GraphQL extension specification allows you to nest files anywhere within GraphQL mutations like this:

这是多部分请求规范的来源。此GraphQL扩展规范允许您在GraphQL突变内的任何位置嵌套文件,如下所示:

{  query: `    mutation($file: Upload!) {      uploadFile(file: $file) {        id      }    }  `,  variables: {    file: File // somefile.jpg  }}

As you can see, adding in a file is as simple as adding in any other type of mutation parameter. To implement this spec, you have to install two parts: one that runs on the client, and another that runs on the server. Here’s what they do:

如您所见,添加文件就像添加任何其他类型的mutation参数一样简单。 要实现此规范,您必须安装两部分:一部分在客户端上运行,另一部分在服务器上运行。 他们的工作如下:

  • The client spec defines how to map any file objects in a mutation into a key that locates where they are in a multipart request.

    客户端规范定义了如何将突变中的任何文件对象映射到键中,以定位它们在多部分请求中的位置。
  • The server spec defines how to parse that map, and make the files re-accessible based on the key provided in the map.

    服务器规范定义了如何解析该映射,并根据映射中提供的密钥使文件可重新访问。

So in apollo-client, you can run a mutation that looks like this:

因此,在apollo客户端中,您可以运行如下所示的突变:

this.props.mutate({variables: {file: yourFile}})

多部分请求规范实现 (Multipart Request Spec Implementations)

If you’re looking to implement the multipart request spec with Apollo, you can easily integrate it with these packages written by Jayden Seric. These are for the JavaScript and Apollo ecosystem.

如果您希望通过Apollo实现多部分请求规范,则可以轻松地将其与Jayden Seric编写的这些软件包集成。 这些是针对JavaScript和Apollo生态系统的。

jaydenseric/apollo-upload-clientapollo-upload-client - Enhances Apollo Client for intuitive file uploads via GraphQL mutations.github.comjaydenseric/apollo-upload-serverapollo-upload-server - Enhances Apollo GraphQL Server for intuitive file uploads via GraphQL mutations.github.com

jaydenseric / apollo上载客户端 apollo上载客户端-增强了Apollo客户端,可通过GraphQL突变直观地上传文件。 github.com jaydenseric / apollo-upload-server apollo-upload-server-增强了Apollo GraphQL Server,可通过GraphQL突变直观地上传文件。 github.com

If you run your GraphQL API through Graphene and Django, you can implement the spec in Python by replacing your GraphQL view with this package I wrote here:

如果通过Graphene和Django运行GraphQL API,则可以通过用我在此处编写的此程序包替换GraphQL视图,从而在Python中实现该规范:

lmcgartland/graphene-file-uploadgraphene-file-upload - Enhances Graphene Django GraphQL Server for intuitive file uploads via GraphQL mutations.github.com

lmcgartland / graphene-file-upload graphene-file-upload-增强了Graphene Django GraphQL Server,可通过GraphQL突变直观地上传文件。 github.com

结论 (Conclusion)

This spec is an easy way to add file upload capability to your GraphQL application. Focus less on how to get your files, and more on what you get to do with them!

该规范是向GraphQL应用程序添加文件上传功能的简便方法。 少集中精力于如何获取文件,而更多地关注与文件的关系!

If you want to talk more, chat about GraphQL or great typefaces, hit me up on twitter @lucasmcgartland. Or find me elsewhere on the web below:

如果您想谈论更多内容,请聊聊GraphQL或出色的字体,请在twitter @ lucasmcgartland上打我。 或在下面的网上其他地方找到我:

Website | Email | LinkedIn | Twitter | Dribbble

网站 | 电邮 | 领英 推特 | 运球

进一步阅读: (Further Reading:)

翻译自: https://www.freecodecamp.org/news/how-to-manage-file-uploads-in-graphql-mutations-using-apollo-graphene-b48ed6a6498c/

 类似资料: