从React应用中使用GraphQL上传文件。

sd

React前端的文件上传能够经过Apollo Upload Client来实现。javascript

GraphQL使咱们开发者可以在前端应用和REST API之间实现一个强大而灵活的抽象层。做为一个3个月前才接触到GraphQL的实习生,我阅读了许多文章、博客文章和GraphQL社区成员准备的指南,了解如何构建GraphQL服务并将其链接到React应用。但这些资源都没有提到使用GraphQL能够上传文件。css

Image for post

文件上传也能够这样说吗?也许...html

当我受命管理和构建一个新的功能,包括使用GraphQL实现文件上传时,我意识到虽然这个功能包含在Apollo Server 2.0中,但大多数关于这个功能的资源都被布置在不一样的资源库中,并且指南也遗漏了重要的步骤。前端

我从阅读官方博客文章开始研究这个功能,并虔诚地按照它的步骤进行研究,但不幸的是,这是我进入神秘错误之海的入口,只由于博客文章不完整。我花了近一周的时间,在github仓库中跳转GraphQL文件上传功能,以找出个人代码有什么问题。java

所以,我决定收集这篇指南,展现经过使用GraphQL突变实现基本的文件上传功能GraphQL服务器和React客户端的必要步骤。另外,谈谈我对GraphQL这个功能的经验,以及为何做为一个公司咱们决定选择不一样的方法。node

在下面的部分中,本指南将带您经过必要的步骤来建立一个GraphQL服务器,该服务器能够处理从React应用程序与Apollo Client发送的文件上传突变。GraphQL服务器要有2种不一样的功能;将文件保存到文件系统中将其流进S3 bucket中react

Basic Architecture

Image for post

全部部件的示意图,更多细节请查看[github repository](https://github.com/epalaz/gra...)。git

在本指南中,咱们的系统将由如下部分组成。
1.带有Apollo客户端包的React应用。
2.使用Apollo服务器包的GraphQL服务器。github

咱们的GraphQL服务器将有能力将上传的文件保存到文件系统中,并将接收到的数据流流进AWS上的S3 Bucket。为此,咱们将有2个查询:singleUploadsingleUploadStreamchrome

Step 1: Preparing GraphQL Server

Setup

要使用apollo-server库建立一个GraphQL服务器,最简单的方法是按照它的官方指南,但我仍是会在这里列出所需步骤。
首先建立一个目录并安装包。

$ mkdir your_dir_name  
    $ cd your_dir_name  
    $ yarn init --yes  
    $ yarn add apollo-server graphql graphql-upload  
    $ yarn add aws-sdk

这组命令应该安装包和建立。下一步就是开始定义出类型定义和解析器。

类型定义和突变解析器

突变的类型定义和填充物查询

咱们定义了2种不一样的突变。singleUpload突变用于上传文件并将其保存到文件系统的一个目录中,而singleUploadStream则用于流式传输到S3 bucket。这些突变采用Upload标量类型,在Apollo Server 2.0中是默认的,因此它的解析是由apollo服务器本身完成的。Apollo服务器将多部分请求形式映射到这个Upload标量,并为文件生成一个承诺。这两个突变都会返回文件类型,该类型由文件名、mimetype编码字段组成,虽然这并不符合现实生活中的日程安排,但返回文件的正确字段表示文件正确上传至GraphQL服务器。

SingleUpload和singleUploadStream突变的解析器

在这些文件上传解析器中,一个关键的细节是文件参数返回的承诺。为了可以读取文件流,咱们应该等待承诺被解析。在这个例子中,两个突变解析器使用了不一样的方法。singleUpload经过使用then()返回承诺,并将解析后的流保存到文件系统中。另外一方面,singleUploadStream使用await等待承诺解析,经过使用文件流将文件上传到S3。这些解析器的另外一个区别是,在解析器函数里面使用await须要将其定义为async,而singleUpload解析器能够保持同步。

注:旧的例子能够显示文件具备filed stream,而不是createReadStream函数。最新的变动请查看graphql-upload repository。变化的PR](https://github.com/jaydenseri...

配置服务器和AWS SDK

这个server.js文件包含了在localhost的4000端口上启动Apollo服务器并配置AWS JavaScript SDK的代码。(更多细节请参考文档)。使用类型定义和突变解析器建立ApolloServer实例应该足以处理文件上传,以便保存在文件系统中并上传到S3。若是你须要进一步帮助在AWS上建立S3 Buckets,请参考这个连接

const { ApolloServer, gql } = require('apollo-server');
    const fs = require('fs')
    const typeDefs = gql`  
      type File {
        filename: String!
        mimetype: String!
        encoding: String!
      }
      type Query {
        _ : Boolean
      }
      type Mutation {
        singleUpload(file: Upload): File!,    
      }
    `;
    const resolvers = {
      Mutation: {
        singleUpload: (parent, args) => {
          return args.file.then(file => {
            const {createReadStream, filename, mimetype} = file
            const fileStream = createReadStream()
            fileStream.pipe(fs.createWriteStream(`./${filename}`))
            return file;
          });
        },
      },
    };
    const server = new ApolloServer({ typeDefs, resolvers });
    server.listen().then(({ url }) => {
      console.log(`\`🚀  Server ready at ${url}`);
    });
    });

您能够经过键入如下内容测试GraphQL服务器

$ cd your_project_dir  
$ node server.js

到你的控制台。这应该启动服务器的端口4000的localhost。在这以后键入localhost:4000到你的浏览器,你应该可以看到Playground页面上,你能够发送查询和突变到服务器进行测试,也能够看到自动生成的文件的基础上。

Image for post

Apollo Server游乐场截图显示定义的突变和查询。

如今,你能够验证你的突变和查询是否被服务器识别,你已经准备好从你的React应用中向服务器发送graphql请求。

尽管graphiql自己的ide不支持,可是可使用altair测试上传文件和查看结果。image.png

Step 2: Creating the React Application

为了轻松地建立咱们的react应用和它的模板代码,咱们将使用户create-react-app工具由Facebook开发。

$ yarn create react-app your-app-name。
$ yarn add apollo-client apollo-upload-client react-apollo graphql-tag

这条命令应该建立一个给定名称的react应用目录,并自动生成模板代码,开始开发咱们的应用。你能够经过输入如下命令来测试这个命令是否成功

$ 纱线开始

这时应该在localhost:3000端口上启动开发服务器,并进行实时更新。

贴图

由create-react-app建立的应用示例。

若是你能看到这个屏幕,说明你的项目已经设置成功,你能够开始编辑这个模板来上传你的文件。

配置Apollo客户端并为突变准备Schemas

import React from 'react';
        import logo from './logo.svg';
        import './App.css';
        import { InMemoryCache } from 'apollo-cache-inmemory'
        import { createUploadLink } from 'apollo-upload-client'
        import {ApolloClient} from "apollo-client"
        import {ApolloProvider, Mutation} from "react-apollo"
        import gql from "graphql-tag"
        const apolloCache = new InMemoryCache()
        const uploadLink = createUploadLink({
          uri: 'http://localhost:4000', // Apollo Server is served from port 4000
          headers: {
            "keep-alive": "true"
          }
        })
        const client = new ApolloClient({
          cache: apolloCache,
          link: uploadLink
        })
        const UPLOAD_FILE = gql`
          mutation SingleUpload($file: Upload) {
            singleUpload(file: $file) {
              filename
              mimetype
              encoding
            }
          }
        `;
        function App() {
          return (
            <div className="App">
              <ApolloProvider client={client}>
                <header className="App-header">
                    <img src={logo} className="App-logo" alt="logo" />
                    <h2>Save Local</h2>
                        <Mutation mutation={UPLOAD_FILE}>
                            {(singleUpload, { data, loading }) => {
                                console.log(data)
                                return (<form onSubmit={() => {console.log("Submitted")}} encType={'multipart/form-data'}>
                                            <input name={'document'} type={'file'} onChange={({target: { files }}) => {
                                                const file = files[0]
                                                file && singleUpload({ variables: { file: file } })
                                            }}/>{loading && <p>Loading.....</p>}</form>)}
                            }
                        </Mutation>
                </header>
              </ApolloProvider>
            </div>
          );
        }
        export default App;

这段代码建立了一个基本的UI,有1个表单,一个是singleUpload,在这个例子中,onChange事件被用来启动文件上传突变函数,但你也能够选择用你所选择的事件来启动它。作文件上传onChange可让你在文件被选中后当即上传。另外一个细节是将表单元素的encTypemultipart/form-data。查看这个连接来阅读关于GraphQL多部分请求规范的更多细节。在设置了这些组件的渲染函数后,你的UI应该看起来有点相似于这样。

贴图

React应用实例的UI

第三步:测试和上传文件

**测试文件系统保存
在测试以前,请确保服务器和react应用程序都已启动并运行。若是没有,请按照步骤1和2启动它们。让咱们尝试用singleUpload**突变上传一个文件,看看它是否保存在服务器文件系统中。

贴图

若是你检查控制台,你应该能够看到GraphQL服务器返回的上传文件信息。这意味着咱们的上传成功了,剩下的事情就是验证服务器是否将文件保存到文件系统中。

贴图

Aaand voila,"no-image.png "文件成功上传并保存到文件系统。
能够经过chrome devtools查看具体的提交内容。看到这个内容,再去阅读graphql文件提交规范,会容易很多。而且,能够参照此规范,使用Vanillajs来编写客户端代码,而不是非要使用React不可。
image.png

相关文章
相关标签/搜索