GraphQL: File Upload & Troubleshooting
All implementations and extensions are based on graphql-multipart-request-spec
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);
Upload scalar
Due to different dependencies, this may cause some error, see Troubleshooting below
type Mutation { singleUpload(file: Upload!): File! } type File { filename: String! mimetype: String! encoding: String! }
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 */ }
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 }, };
Possibly you included one lib which ALREADY implemented Upload Type, so you just need to delete scalar Upload
You forget to add the scalar Upload
- 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.
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", }
- 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
留言板
PLACE_HOLDER
PLACE_HOLDER
PLACE_HOLDER
PLACE_HOLDER