apollographql / apollo-ios

📱  A strongly-typed, caching GraphQL client for iOS, written in Swift.
https://www.apollographql.com/docs/ios/
MIT License
3.87k stars 717 forks source link

Uploading files with apollo #3408

Closed eugeneekus closed 1 month ago

eugeneekus commented 2 months ago

Summary

Good morning, I've some issues with file uploading using Apollo

Version

0.53

Steps to reproduce the behavior

I have mutation with attachment parameter which is Upload. I set it as GraphQlFile. Also I created extension to make encodable GraphQLFile. I get this error in that case.

Variable $sendBill of type SendBillinput! was provided invalid value for attachment

var imageData = UIImage(named: "tutorialImage1")?.jpegData(compressionQuality: 0.5)

        let file = GraphQLFile(
            fieldName: "file", // Must be the name of the field the file is being uploaded to
            originalName: "image.png",
            mimeType: "image/jpeg", // <-defaults to "application/octet-stream"
            data: imageData!
        )

        sendBill = SendBillInput(amount: amount, contact: contact, invoice: invoice, note: note, tips: tips, showFeedbackHub: showFeedbackHub, subtype: subtype, allowedPayments: allowedPayments, items: inputItems, attachment: file)

        Network.shared.apollo.perform(mutation: SendBillMutation(sendBill: sendBill)) { result in
// Extension to make GraphQLFile conform to JSONEncodable
extension GraphQLFile: JSONEncodable {
    public var jsonValue: JSONValue {
        var jsonObject = JSONObject()
        jsonObject["fieldName"] = self.fieldName
        jsonObject["originalName"] = self.originalName
        jsonObject["mimeType"] = self.mimeType
        if let data = self.data {
            jsonObject["data"] = data.base64EncodedString()
        } else if let fileURL = self.fileURL {
            jsonObject["fileURL"] = fileURL.absoluteString
        }
//        jsonObject["contentLength"] = self.contentLength
        return jsonObject
    }
}

Another thing that I tried was using .upload method, didn't get any errors but my server expected attachment file inside bill input and didn't get it. Can you pls help me? Thank you

var sendBill = SendBillInput(amount: amount, contact: contact, invoice: invoice, note: note, tips: tips, showFeedbackHub: showFeedbackHub, subtype: subtype, allowedPayments: allowedPayments, items: inputItems)

var imageData = UIImage(named: "tutorialImage1")?.jpegData(compressionQuality: 0.5)

let file = GraphQLFile(
    fieldName: "file", // Must be the name of the field the file is being uploaded to
    originalName: "image.png",
    mimeType: "image/jpeg", // <-defaults to "application/octet-stream"
    data: imageData!
)

Network.shared.apollo.upload(operation: SendBillMutation(sendBill: sendBill), files:[file]) { result in

Logs

No response

Anything else?

No response

AnthonyMDev commented 2 months ago

Hi there @eugeneekus. Can you try setting the fieldName property to attachment. It looks like that is the name of the field on your input object.

Whenever someone has questions about file uploads, I am obligated to say: As stated in our docs, file uploads in GraphQL have a lot of limitations, which is why we don't recommend using them in production. We'll still try to help you get this working if you need to, but you might be better off uploading your files seperately.

eugeneekus commented 1 month ago

For some reason when I do it like this (use file in input and in , files:[file]) responce is 403 all the time, app tries to refresh token and retry but 403 again and again. Any ideas? Thank you for help!

        var imageData = UIImage(named: "tutorialImage1")?.jpegData(compressionQuality: 0.5)

        let file = GraphQLFile(
            fieldName: "attachment", // Must be the name of the field the file is being uploaded to
            originalName: "image.png",
            mimeType: "image/jpeg", // <-defaults to "application/octet-stream"
            data: imageData!
        )

        var sendBill = SendBillInput(amount: amount, contact: contact, invoice: invoice, note: note, tips: tips, showFeedbackHub: showFeedbackHub, subtype: subtype, allowedPayments: allowedPayments, items: inputItems, attachment: file)

        Network.shared.apollo.upload(operation: SendBillMutation(sendBill: sendBill), files:[file]) { result in
AnthonyMDev commented 1 month ago

It looks like changing the fieldName to attachment was the correct solution for the error with Apollo iOS. Since before the request was invalid, and now you are sending a valid request to the server at least.

The 403 is a "Forbidden" status code, indicating that your server is not accepting the request for some reason. That is something you need to resolve with your backend. Perhaps your request authentication is invalid or your server isn't set up to receive GraphQL file uploads properly?

I don't think there is much more for us to assist you with here, since the request is being properly sent now. If you think this is still an Apollo iOS issue, let us know why and we can re-open this issue.

github-actions[bot] commented 1 month ago

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo iOS usage and allow us to serve you better.