kamilkisiela / apollo-angular

A fully-featured, production ready caching GraphQL client for Angular and every GraphQL server 🎁
https://apollo-angular.com
MIT License
1.5k stars 309 forks source link

FileUpload failing to upload file #1863

Closed boomdizz closed 1 year ago

boomdizz commented 1 year ago

Describe the bug FileUpload mutation is failing from within Angular code, though succeeds with external tools like Altair.

I am using Angular/Apollo(Graphql) ("apollo-angular": "^4.1.0", "@apollo/client": "^3.7.1") on the client side and Django/Graphene (Django 4.1.2, graphene 3.1.1, graphene-django 3.0.0, graphql-core 3.2.3, graphql-relay 3.2.0) on the server side. Also using graphene-file-upload (1.3.0) package to support the upload of files to the server as an extension of Graphene. The mutation is working flawlessly when executed through tools like Altair, but when I try to use it in my Typescript/Javascript/Angular code, I am getting an empty dict being sent to the server-side.

I have tried to follow instructions for FileUpload in the documentation except that I have a mutation for the upload instead of a query. In my Angular service class, the function for the upload is:

  uploadFile(agFile: File): Observable<FetchResult<any>>  {
    console.log(agFile)
    return this.apollo.mutate({
      mutation: UPLOAD_NEW_FILE,
      variables: {
        newFile: agFile
      },
      context: {
        userMultipart: true
      }
    });

where

const UPLOAD_NEW_FILE = gql `
mutation UploadNewFile($newFile: Upload!) {
  uploadNewFile(newFile: $newFile) {
    success
  }
}`;

And I am calling this service method from my Angular component:

  onFileUpload(event) {
    const myFile = event.target.files[0]
    this.configSvc.uploadFile(myFile).subscribe(({ data }) => {
      console.log("Upload of package was " + data.success)
    })
  }

onFileUpload is invoked from an 'input type="file" HTML element. I have printed (console.log) the myFile variable in onFileUpload handler function and the 'agFile' variable in the uploadFile service function right before the mutation call, and they indeed are file objects. But for whatever reason, when apollo picks it up it makes it into an empty dict. Debugging on the graphene/Django side confirms an empty dict.

I am setting up the httpLink (in app.module.ts) with 'extractFiles' as per the documentation, though I am not sure what it does:

import  extractFiles from 'extract-files/extractFiles.mjs'
    .
    .
        // Create an http link:
        const http = httpLink.create({
          uri: '/graphql/',
          extractFiles
        })

I am not sure but I wonder if I need to declare a custom scalar of type 'Upload' (see UPLOAD_NEW_FILE above), but have never written one, so not sure where to begin.

Don't know if this is a bug or whether I am missing some pieces :>

To Reproduce I have a big Angular application that uses apollo-angular and apollo client extensively and if the description above does not suffice, I can try recreating a reproduce scenario.

Expected behavior

Expect the file to be uploaded by the mutation, much like I can do with external tools (e.g, Altair)

Environment:

├── @angular/cli@14.2.8
├── @angular/core@14.2.8
├── @apollo/client@3.7.1
├── apollo-angular@4.1.0
├── graphql@16.6.0
└── typescript@4.8.4

Additional context

boomdizz commented 1 year ago

There is no problem/bug with the implementation of this package. I was using 'userMultipart' instead of 'useMultipart' in the context for the mutation (see first code snippet in my Issue creating post) and it took me a while to figure that out.

I have fully documented my solution in Stackoverflow just in case anyone else is trying to solve the problem as well.

boomdizz commented 1 year ago

Please close the issue as a non-issue/won't fix.....