📜  grapql 文件上传 - Javascript (1)

📅  最后修改于: 2023-12-03 14:41:38.067000             🧑  作者: Mango

GraphQL 文件上传 - JavaScript

在 GraphQL 的设计过程中,有一项重要的需求就是文件上传。然而,和基于 REST 的 API 不同,GraphQL 并没有内置的文件上传功能。因此,我们需要使用一些特定的工具和技术来处理文件上传。

本文将介绍使用 JavaScript 实现 GraphQL 文件上传的方法,包括前端和后端的代码实现。

前端实现

前端实现文件上传主要使用了 apollo-upload-client 这个库。这个库是基于 fetch 的 GraphQL 客户端,可以支持文件上传。

首先,我们需要安装这个库:

npm install apollo-upload-client

然后,在客户端使用的地方导入这个库,同时创建一个 ApolloUploadLink,把其作为 ApolloClient 的链接,就可以实现文件上传。

以下是一个示例代码:

import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloLink } from 'apollo-link';
import { createUploadLink } from 'apollo-upload-client';

const uploadLink = createUploadLink({ uri: '/graphql' });

const client = new ApolloClient({
  link: ApolloLink.from([uploadLink]),
  cache: new InMemoryCache(),
});

在这个示例中,我们使用 createUploadLink 创建了一个上传链接。这个链接会将上传的文件转成 FormData 进行传递。

现在我们可以定义一个 GraphQL mutation 来进行文件上传了。以下是一个示例代码:

mutation uploadFile($file: Upload!) {
  uploadFile(file: $file) {
    id
    filename
    mimetype
    encoding
    url
  }
}

这个 mutation 的参数是一个 Upload 对象,它会在客户端被转成一个 File 对象进行传递。

在使用 ApolloClient 执行这个 mutation 时,我们可以按照以下方式进行调用:

const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0]; // 获取文件对象

const response = await client.mutate({
  mutation: gql`
    mutation uploadFile($file: Upload!) {
      uploadFile(file: $file) {
        id
        filename
        mimetype
        encoding
        url
      }
    }
  `,
  variables: {
    file,
  },
});

在这个示例中,我们获取了用户上传的文件对象,然后在进行 mutate 调用时将它作为参数传递。

后端实现

在服务器端,我们需要使用支持文件上传的 GraphQL 库来处理前端传递过来的文件。

在本文中,我们使用了 apollo-server-express 这个库来实现 GraphQL 服务器。同时,我们使用了 graphql-upload 这个库来处理文件上传。

首先,我们需要安装这两个库:

npm install apollo-server-express graphql graphql-upload

在代码中,我们需要先创建一个 GraphQL schema,这个 schema 中需要定义支持文件上传的 mutation。以下是一个示例代码:

const typeDefs = gql`
  scalar Upload

  type File {
    id: ID!
    filename: String!
    mimetype: String!
    encoding: String!
    url: String!
  }

  type Mutation {
    uploadFile(file: Upload!): File!
  }
`;

在这个示例中,我们定义了一个名为 Upload 的 scalar,在 mutation 中使用这个 scalar 作为参数类型。

接着,我们需要创建一个 GraphQLUpload 对象,作为 schemaDirectives 的一个参数传递给 ApolloServer。以下是一个示例代码:

const { ApolloServer } = require('apollo-server-express');
const { GraphQLUpload } = require('graphql-upload');

const server = new ApolloServer({
  typeDefs,
  resolvers,
  schemaDirectives: {
    upload: GraphQLUpload,
  },
});

在这个示例中,我们创建了一个 GraphQLUpload 对象,并将它作为一个 directive 传递给了 ApolloServer

最后,在 resolver 中,我们需要使用 createWriteStream 来将上传的文件保存到磁盘中。以下是一个示例代码:

const resolvers = {
  Mutation: {
    uploadFile: async (parent, { file }) => {
      const { createReadStream, filename, mimetype, encoding } = await file;
      const stream = createReadStream();
      const id = shortid.generate();
      const path = `${UPLOAD_DIR}/${id}-${filename}`;
      const url = `http://localhost:4000/uploads/${id}-${filename}`;

      await new Promise((resolve, reject) =>
        stream
          .on('error', (error) => {
            unlink(path, () => {
              reject(error);
            });
          })
          .pipe(createWriteStream(path))
          .on('error', (error) => reject(error))
          .on('close', () => resolve()),
      );

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

在这个示例中,我们使用了 Node.js 内置的 fs.createReadStreamfs.createWriteStream 方法来实现文件读取和保存功能。在 createWriteStream 中,我们需要传入保存文件的位置。

结语

通过上述方式,我们就可以实现 JavaScript 中的 GraphQL 文件上传了。需要注意的是,在实际的应用中,我们需要考虑一些文件上传的细节问题,如文件大小、文件类型、文件名等。

希望这篇文章对您有所帮助。