使用 Relay Modern 和 GraphQL 上传文件

File uploading with Relay Modern & GraphQL

所以我已经研究了两天,但在 Java 方面还不够精明,无法完全理解解决此问题的方法。在客户端,我发现了一些 excellent user documentation 并且相信我已经按顺序排列了正确的部分,但是在处理服务器中的入站 multipart/formdata 时,我有点迷路了。

我的应用程序的基础是 HowToGraphQL Java tutorial as I feel they did a great job organizing their code base and make things very simple and understandable. Unfortunately file uploading is not an area they cover, and per a maintainer of the graphql-java package, no plans exist to directly support this feature

但这并不是说这是不可能的。 GraphQL 规范旨在作为指南,社区如何选择调用规范取决于他们。许多人已经成功地合并了文件上传,尽管通常是通过包含 custom middleware

不幸的是,我的障碍可能只是缺乏领域知识。我主要使用 JavaScript 和 Python 工作,并且主要在 Java 方面有学术经验。不完全确定从哪里开始,但我想我需要追踪我认为绑定到 SimpleGraphQLServlet 中的响应对象 class 并找到一种方法来提取入站文件对象。

希望得到更多专家建议或帮助提出解决方案。我还没有在 SO 上找到任何可靠的基于 Java 的片段来解决这个问题,所以解决这个问题可能会让其他尝试采用这个平台的人受益。

编辑:

可能找到了一种方法来做到这一点,但还没有制定出具体细节。在扩展 SimpleGraphQLServlet class 的 GraphQLEndpoint class 中,我们公开了 doPost() 方法。然而,提取数据最终会导致一系列错误,第一个错误是通过@MultipartConfig 注释解决的,然而下一个错误让我再次停滞不前。 "Missing content for MultiPart request."

这个doPost()方法好像是在突变发生后被调用的,所以即使我设法提取了文件数据,数据似乎也放错了地方。此外,我想知道丢失的内容是否是消耗 post 数据的突变的结果,假设它甚至到达了。

然而,所有其他参数都完好无损,因此只需访问此文件即可。

目前,不幸的是,适用于我的解决方案并没有完全遵循我认为的最佳实践,即使用可上传、作为 multipart/form-data 发送,然后在服务器上注入中间件。但是我能够传输文件数据,所以这是一个很好的开始。

最终我选择将上传的文件编码为 base64,然后通过 GraphQL 突变将数据作为 String 类型发送,然后在接收后我能够解码 base64 字符串。

目前我所看到的只是正在传输的文件内容,而不是元数据。由于某些元数据对我很有价值,因此需要将其与 base64 字符串一起发送,或者我可能只是忽略了这个元素,它确实存在。

无论哪种方式,我都会留下一些我在解决这个问题时发现有用的资源,如果其他人遇到这个问题,它们可能会很有用。我不认为我当前的解决方案是这里的真正答案,所以也许随着这些包的发展,我们会及时看到更好的方法来通过 Relay/graphql-java.

上传文件

Decode Base64 data in Java

关于 HowToGraphQL 的 Java 教程不幸地过时了。我正在努力更新它(我是原作者),但这需要时间。 当前的最佳实践是在以模式优先方式工作时直接使用 graphql-java 的 RuntimeWiring*。这里有一些基本文档:http://graphql-java.readthedocs.io/en/v6/schema.html

无论如何,处理文件上传的方式没有改变:将整个 HttpServletRequest 对象或只是二进制部分粘贴到共享上下文中:

graphQL.execute(ExecutionInput.newExecutionInput()
    .query(operation)
    .context(request.getPart("file")) //add the binary to the context
    .build());

稍后,在 DataFetcher 中,您可以通过以下方式获取它:DataFetchingEnvironment#getContext:

Part file = environment.getContext();
file.getInputStream(); //do something with the binary content

当然,您可以使用其他一些(动态)结构作为上下文,而不是直接使用二进制文件。

这种处理上传的侧载方式是使用 JSON 作为传输格式的结果,并且 JSON 是文本格式。与文件下载通常在 GraphQL 之外处理的原因相同(其中响应仅包含 ID 或启动下载所需的 URL)。参考服务器实现包括使用相同策略的示例。
据我所知,目前还没有非 JSON GraphQL 客户端。

*对于代码优先,graphql-spqr(我的项目)仍然是最方便的方式。