本文介绍如何在Apollo GraphQL中实现文件的传输
文件传输在GrapqhQL中官方建议
文章Apollo Server File Upload Best Practices提及了实现文件上传的几种方式,分别是:
- Signed URLs
- Using an image upload service
- Multipart Upload Requests
本文介绍我所尝试过的第一种和第三种。
用grapqhl-upload的方式
graphql-upload是一个第三方的库,可以用来传输多个文件,也是实现文件传输的最简单方式。
在《Principled GraphQL》中,Apollo创始人们对Data Graph原则的指南中建议我们“将GraphQL层与服务层分离”。通常情况下,在生产客户端-服务器架构中,客户端不直接与后端服务进行通信。通常,我们使用一个额外的层来“将负载平衡、缓存、服务定位或API密钥管理等关注点委派给单独的层”。
对于新的业余项目(不太重要或概念验证),通常情况下,面向客户端的GraphQL服务也是执行业务逻辑、直接与数据库交互(可能通过ORM)并返回解析器所需数据的后端服务。虽然我们不建议在生产环境中使用这种架构,但这是开始学习Apollo生态系统的一种不错的方式。
注意:除非明确使用csrfPrevention: true配置Apollo Server,否则此方法容易受到CSRF变异攻击的影响。
下面给出示例:
首先安装graphql-upload:
npm install graphql-upload
在定义graph schema时,添加Upload类型:
scalar Upload
Javascript code:
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
const {
GraphQLUpload,
graphqlUploadExpress, // A Koa implementation is also exported.
} = require('graphql-upload');
const { finished } = require('stream/promises');
const { ApolloServerPluginLandingPageLocalDefault } = require('apollo-server-core');
const typeDefs = gql`
# The implementation for this scalar is provided by the
# 'GraphQLUpload' export from the 'graphql-upload' package
# in the resolver map below.
scalar Upload
type File {
filename: String!
mimetype: String!
encoding: String!
}
type Query {
# This is only here to satisfy the requirement that at least one
# field be present within the 'Query' type. This example does not
# demonstrate how to fetch uploads back.
otherFields: Boolean!
}
type Mutation {
# Multiple uploads are supported. See graphql-upload docs for details.
singleUpload(file: Upload!): File!
}
`;
const resolvers = {
// This maps the `Upload` scalar to the implementation provided
// by the `graphql-upload` package.
Upload: GraphQLUpload,
Mutation: {
singleUpload: async (parent, { file }) => {
const { createReadStream, filename, mimetype, encoding } = await file;
// Invoking the `createReadStream` will return a Readable Stream.
// See https://nodejs.org/api/stream.html#stream_readable_streams
const stream = createReadStream();
// This is purely for demonstration purposes and will overwrite the
// local-file-output.txt in the current working directory on EACH upload.
const out = require('fs').createWriteStream('local-file-output.txt');
stream.pipe(out);
await finished(out);
return { filename, mimetype, encoding };
},
},
};
async function startServer() {
const server = new ApolloServer({
typeDefs,
resolvers,
// Using graphql-upload without CSRF prevention is very insecure.
csrfPrevention: true,
cache: 'bounded',
plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
});
await server.start();
const app = express();
// This middleware should be added before calling `applyMiddleware`.
app.use(graphqlUploadExpress());
server.applyMiddleware({ app });
await new Promise<void>((r) => app.listen({ port: 4000 }, r));
console.log(`
标签:const,URL,await,文件传输,upload,Graphql,file,graphql,Apollo
From: https://www.cnblogs.com/Asp1rant/p/17418809.html