GraphQL: File Upload & Troubleshooting
GraphQL File Upload
All implementations and extensions are based on graphql-multipart-request-spec
Client
ApolloClient Setup
Client is using apollo-upload-client which implemented graphql-multipart-request-spec
Replace HttpLink
with createUploadLink
Those two do the same thing, feel free to replace it!
import {
ApolloClient,
InMemoryCache
} from '@apollo/client';
import {
createUploadLink
} from 'apollo-upload-client';
const client = new ApolloClient(config);
Add Scalar
Upload scalar
Due to different dependencies, this may cause some error, see Troubleshooting below
Add Schema
type Mutation {
singleUpload(file: Upload!): File!
}
type File {
filename: String!
mimetype: String!
encoding: String!
}
Frontend
Provide an input or use other frontend components to select a file:
<input type="file" onchange={fileUpload}>
Then validate the selected file:
const uploadOnChange = async (files: File[]) => {
if (files.length === 0) return
if (files.filter((file) => file.size > 10 * 1024 * 1024).length > 0) {
/* throw error: file size exceed */
return
}
if (
files.filter(
(file) => [ `image/png` , `image/jpeg` ].findIndex(
(type) => file.type === type
) === -1
).length > 0
) {
/* throw error: unacceptable file type */
return
}
/* trigger mutation here */
}
Backend
GraphQL port it to assets server
If you are using Javascript, skip the import of
graphql-upload
If you are using Typescript, you can use graphql-upload for type check, which implemented graphql-multipart-request-spec
import { FileUpload } from "graphql-upload";
const uploadFile = async (filePromise: {
file: FileUpload;
}): Promise<boolean> => {
try {
const { file }: { file: FileUpload } = await filePromise;
const fileReadStream = file.createReadStream(); // get the file readstream
/* ----------------------------- `*/
/* Option 1: You can save the file on current server */
/* const writeStream = fs.createWriteStream('fakepath/output.png') */
/* Convert stream to file */
/* readStream.pipe(writeStream) */
/* ----------------------------- */
/* Option 2: You can port the file to assets server if you need */
const formData = new FormData();
formData.append("attachmentData", fileReadStream, file.filename);
await http.post( `assetsServer/fileUpload` , formData, {
headers: {
...formData.getHeaders(),
},
timeout: 30000,
});
return true;
} catch (error) {
return false;
}
};
const resolvers = {
Query: {
files: () => {
// Return the record of files uploaded from your DB or API or filesystem.
}
},
Mutation: {
uploadFile
},
};
Troubleshooting
There can be only one type named "Upload"
Possibly you included one lib which ALREADY implemented Upload Type, so you just need to delete scalar Upload
Unknown type "Upload". Did you mean "Float"?
You forget to add the scalar Upload
scalar Upload
always causes error :(
- If I add it ->
Error: There can be only one type named "Upload"
- If I remove it ->
Error: Unknown type "Upload". Did you mean "Float"?
Oh you got some tricky dependencies.
Try use other names like:
scalar FileUpload
That may help your issue, GraphQL may regard it as custom scalar.
createReadStream() crashes-RangeError: Maximum call stack size exceeded
RangeError: Maximum call stack size exceeded
at _openReadFs (internal/fs/streams.js:1:1)
This is due to outdated dependency of fs-capacitor
.
To prevent future compatibility issue, set resolutions
in package.json
:
"resolutions": {
"graphql-upload": "11.0.0"
},
Be aware that resolutions property is currently only handled by yarn package manager, not by npm
with npm, you have to preinstall an aditionnal module to force resolutions :
"scripts": {
"preinstall": "npx npm-force-resolutions",
}
References
- https://github.com/jaydenseric/apollo-upload-client#function-createuploadlink
- https://github.com/jaydenseric/graphql-multipart-request-spec
- https://www.apollographql.com/docs/apollo-server/data/file-uploads/
- https://medium.com/@enespalaz/file-upload-with-graphql-9a4927775ef7
- https://github.com/apollographql/apollo-server/issues/3508
相关文章
- Springboot&websocket实现IP数据实时统计
- iOS小技能:本地化(Internationalization & Localization)
- ECCV 2022 | 清华&Meta提出HorNet,用递归门控卷积进行高阶空间相互作用
- SP11444 MAXOR - MAXOR & bzoj 2741 【FOTILE模拟赛】L
- C++20 以 Bazel & Clang 开始
- 常用#免费%代理IP库&整理*收藏——实时@更新(大概)
- GoLang17 - Go 语言递归函数&类型转换
- Python 线程&进程与协程
- C&C++内存管理
- 【字符串匹配算法:BF & KMP】
- 7 Papers & Radios | 谷歌开源机器人领域transformer;DeepMind推出剧本写作AI
- 7 Papers & Radios | 史上最强三维人脑地图;3D渲染图转真实图像
- ORA-01251: Unknown File Header Version read for file number string ORACLE 报错 故障修复 远程处理
- ORA-19810: Cannot create temporary control file string in DB_RECOVERY_FILE_DEST ORACLE 报错 故障修复 远程处理
- 马化腾的成功法宝&quot;信念“详解程序员
- Linux操作管理:掌握File命令(linux命令file)
- AMP MySQL升级提升数据库性能的必要之举(amp mysql升级)
- php&java(一)
- 基于Jquery的简单&简陋Tabs插件代码