Graphql文件上传

apollo

2019年用了Graphql作为web项目api开发后,前端编程效率有了质的提升。Graphql使得数据的查询,修改等操作变得极其灵活,但Graphql 对于文件上传的支持不是很好,于是笔者花了点时间整理了一个解决方案。

Graphql Multipart Request 规范


为了统一graphql上传文件服务端和客户端接口,好在Apollo社区提出了一份规范jaydenseric/graphql-multipart-request-spec: A spec for GraphQL multipart form requests (file uploads).。

该规范定义了文件上传的数据格式。

文件上传定义为一个graphql的mutation 官方叫Operations。

  1. Operations 是一个Json对象,其中的files设为null。
  2. map: 也是一个Json对象定义了一次上传所有的文件,例如
{ "0": ["variables.files.0"], "1": ["variables.files.1"] }
  1. File fields: 是对应Operations中所有的文件。

工作原理


上传功能分为两部分服务端和客户端,分别按照规范实现接口。

客户端:在客户端,把上传的文件翻译成一个Operations然后发送一个multipart 请求给服务端。

服务端:服务端收到一个multipart请求,按照Operations的格式提取文件。

例子


首先定义服务端 graphql schema。

const { ApolloServer, gql } = require('apollo-server');

const typeDefs = gql`
  type File {
    filename: String!
    mimetype: String!
    encoding: String!
  }
  type Query {
    uploads: [File]
  }
  type Mutation {
    singleUpload(file: Upload!): File!
  }
`;

其中 Upload为一个Scalar Type 不做任何序列化的操作。

const resolvers = {
  Query: {
    files: () => {
      // Return the record of files uploaded from your DB or API or filesystem.
    }
  },
  Mutation: {
    async singleUpload(parent, { file }) {
      const { stream, filename, mimetype, encoding } = await file;

      // 1. Validate file metadata.

      // 2. Stream file contents into cloud storage:
      // https://nodejs.org/api/stream.html

      // 3. Record the file upload in your DB.
      // const id = await recordFile( … )

      return { filename, mimetype, encoding };
    }
  },
};

以上为 resolver 部分的代码。

客户端代码,需要按照apollo-upload-client(https://github.com/jaydenseric/apollo-upload-client) 这个包。


const { ApolloClient } = require('apollo-client')
const { InMemoryCache } = require('apollo-cache-inmemory')
const { createUploadLink } = require('apollo-upload-client')

const client = new ApolloClient({
  cache: new InMemoryCache(),
  link: createUploadLink()
})

import gql from 'graphql-tag'
import { Mutation } from 'react-apollo'

export const UPLOAD_FILE = gql`
  mutation uploadFile($file: Upload!) {
    uploadFile(file: $file) {
      filename
    }
  }
`;

const uploadOneFile = () => {
  return (   
    
      {uploadFile => (
        
          validity.valid && uploadFile({ variables: { file } });
        }
       />
      )}
    
  );
};

apollo client 需要通过createUploadLink来配置,当一个 input file 触发onChange时候,发送文件上传mutation。

你可能感兴趣的:(Graphql文件上传)