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",
}