I am using Angular/Apollo(Graphql) on the client side and Django/Graphene on the server side. Also using graphene-file-upload 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 am trying to use it in my Typescript/Javascript/Angular code, I am getting an empty dict being sent to the server-side.
const UPLOAD_NEW_FILE = gql `
mutation UploadNewFile($fileToUpload: Upload!) {
uploadNewFile(file: $fileToUpload) {
success
}
}`;
// This function is part of a Service class that interfaces with the Apollo
// graphql client
uploadFile(agFile: File): Observable<FetchResult<any>> {
return this.apollo.mutate({
mutation: UPLOAD_NEW_FILE,
variables: {
fileToUpload: agFile
}
});
And I am calling this method like this:
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.
Any help is much appreciated.
I was finally able to get it to work. Posting the solution here as it may help others. This is for Angular using Apollo client ("apollo-angular": "^4.1.0", "@apollo/client": "^3.7.1") and a Django/Graphene backend/server (Django 4.1.2, graphene 3.1.1, graphene-django 3.0.0, graphql-core 3.2.3, graphql-relay 3.2.0) with graphene-file-upload (1.3.0) extension of graphene.
In my Angular service class, the function for the upload is:
uploadFile(agFile: File): Observable<FetchResult<any>> {
return this.apollo.mutate({
mutation: UPLOAD_NEW_FILE,
variables: {
newFile: agFile
},
context: {
useMultipart: true // Needed to support multipart upload.
}
});
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.
In app.module.ts where the apollo client is created and configured, I setup the httpLink for the apollo client like this:
import extractFiles from 'extract-files/extractFiles.mjs';
import isExtractableFile from 'extract-files/isExtractableFile.mjs';
.
.
.
const http = httpLink.create({
uri: '/graphql/',
extractFiles: (body) => extractFiles(body, isExtractableFile)
})
.
.
That is all the code in the client. For the server side, the code example in the README file for the graphene-file-upload package works well without any modifications (hence not reproducing it here). I tested/verified it with the Altair client before trying to integrate the mutation request into the UI code.