Search code examples
typescriptnuxt.jsapollovue-apollo

Apollo can't upload file in Object of class


In my project I try to upload files in a multipart request via Graphql. The problem is, when I create an object of a class, which contains a File, the file is not uploaded. When it is just an Object without a class it is working.

This is working:

const upload = {
   file: new File()
};
apollo.mutate({
   mutation,
   variables:{
      fileParam: upload
   }
});

This is not working:

class FileWrapper{
   constructor(public file: File){}
}
const upload = new FileWrapper(new File());
apollo.mutate({
   mutation,
   variables:{
      fileParam: upload
   }
});

This is working:

class FileWrapper{
   constructor(public file: File){}
}
const upload = new FileWrapper(new File());
apollo.mutate({
   mutation,
   variables:{
      fileParam: {...upload}
   }
});

Packages I am using:

    "nuxt": "^2.0.0",
    "@nuxtjs/apollo": "^4.0.1-rc.1",

I replaced the standard HttpLink with createUploadLink like so:

  return ApolloLink.from([
    mutationTrackerLink(getModule(MutationTrackState, ctx.store), providerName),
    queueLink,
    serializingLink,
    retryLink,
    authLink,
    createUploadLink({
      uri: `${endpoint}/graphql`,
    }),
  ]);

I tried to remove all the other links, but with the same result.


Solution

  • I traced the problem back to the package: https://github.com/jaydenseric/extract-files It checks if object.constructor === Object. This is not the case when you have an object of a class and therefore it doesn't look deeper into the object.

    For now I solved it with this function which makes the object of a class to an anonymous object. I mostly copied this function form another StackOverflow post (unfortunatley I forgot which one) and modified it slightly.

    public static copyToAnonymusObject(obj: any) {
        let copy: any;
    
        // Handle the 3 simple types, and null or undefined
        if (obj === null || typeof obj !== 'object') return obj;
    
        // Handle File
        if (obj instanceof File) {
          return obj;
        }
    
        // Handle Date
        if (obj instanceof Date) {
          copy = new Date();
          copy.setTime(obj.getTime());
          return copy;
        }
    
        // Handle Array
        if (Array.isArray(obj)) {
          copy = [];
          for (let i = 0, len = obj.length; i < len; i++) {
            copy[i] = this.copyToAnonymusObject(obj[i]);
          }
          return copy;
        }
    
        // Handle Object
        if (obj instanceof Object) {
          copy = {};
          Object.keys(obj).forEach((key) => {
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
              copy[key] = this.copyToAnonymusObject(obj[key]);
            }
          });
          return copy;
        }
    
        throw new Error("Unable to copy obj! Its type isn't supported.");
      }