📅  最后修改于: 2023-12-03 14:41:38.067000             🧑  作者: Mango
在 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.createReadStream
和 fs.createWriteStream
方法来实现文件读取和保存功能。在 createWriteStream
中,我们需要传入保存文件的位置。
通过上述方式,我们就可以实现 JavaScript 中的 GraphQL 文件上传了。需要注意的是,在实际的应用中,我们需要考虑一些文件上传的细节问题,如文件大小、文件类型、文件名等。
希望这篇文章对您有所帮助。