Search code examples
swiftalamofirequickblox

Upload file to Quickblox without SDK, ideally with Alamofire


I am trying to upload an sqlite file to Quickblox servers from an OS X project written in Swift. I've already figured this out on iOS with the Quickblox iOS SDK:

                    let file = QBCOFile()
                    file.name = "ThisFileName"
                    file.contentType = "sqlite"
                    let theData = NSData(contentsOfFile: originalPath)
                    file.data = theData
                    QBRequest.uploadFile(file, className: "MyClassName", objectID: cusObjID, fileFieldName: "FieldName", successBlock: {(response:QBResponse,fileUploadInfo:QBCOFileUploadInfo?) in

                        }, statusBlock: nil, errorBlock: {(response:QBResponse) in

                            showError()
                    })

With OS X, I've been using Alamofire and have gotten other requests to work but not this one. The description of the request on their API page (https://quickblox.com/developers/Custom_Objects#Upload.2FUpdate_file) is this:

curl -X POST -H "QB-Token: e7cde5f7f5b93f3fa5ac72a281777cbf0f908374" -F "field_name=avatar" -F 'file=@"ava.jpg"' https://api.quickblox.com/data/<Class_name>/<record_id>/file.json

One main difference between this description and others are the "-F"s that I'm not sure what to do with. Here is one variation of the code I've tried so far:

Alamofire.upload(Method.POST, "https://api.quickblox.com/data/MyClassName/\(cusObjID)/file.json",
                            headers: ["QB-Token":realToken],
                            multipartFormData: { multipartFormData in

                                if let valData = "FieldName".dataUsingEncoding(NSUTF8StringEncoding) {
                                    multipartFormData.appendBodyPart(data: valData, name: "field_name")
                                }
                                multipartFormData.appendBodyPart(data: theData, name: "ThisFileName", fileName: "ThisFileName.sqlite", mimeType: "multipart/form-data")
                            },
                            encodingCompletion: { encodingResult in
                                switch encodingResult {
                                case .Success(let upload, _, _):
                                    upload.responseJSON { response in
                                        debugPrint(response)
                                    }
                                case .Failure(let encodingError):
                                    print(encodingError)
                                }
                            }

I know the token and the custom object ID (cusObjID) work because I've used them in other requests. I've tried tons of variations on the "appendBodyPart" parts, and they've all given me this result:

[Result]: SUCCESS: {
errors =     (
    "Wrong arguments"
);
}

and the response has included

Status = "404 Not Found";

I have seen some answers here on StackOverflow suggesting Alamofire might not work for this type of upload, so if there's some other way to accomplish this, that would be great, too. Really, any way to accomplish what I did on iOS with the iOS Quickblox SDK is what I'm looking for.

UPDATE

Using an edit of the last answer of this question (Uploading file with parameters using Alamofire), I've been able to get the progress to update as the file uploads

.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
                                Swift.print("\(totalBytesWritten) / \(totalBytesExpectedToWrite)")
                            }

but nonetheless I'm still getting the same errors. By the way, this is what my request header looks like from the successful iOS version:

Request headers: {
    "Accept-Language" = "en-US;q=1";
    "Content-Length" = 6488309;
    "Content-Type" = "multipart/form-data; boundary=Boundary+88AB02F344BB7C4E";
    "QB-Token" = b6f06b9e6e45c839aecc89019add6bd1;
    "User-Agent" = "App Name/2.1 (iPhone; iOS 9.3; Scale/2.00)";
}

Solution

  • OK, I struggled a while with Alamofire and never got it to do what I wanted it to. I switched to a different framework, SwiftHTTP (https://github.com/daltoniam/SwiftHTTP), that was able to complete the task effortlessly (about as easily as with the Quickblox iOS SDK):

    do {
         let opt = try HTTP.POST("https://api.quickblox.com/data/MyClassName/\(cusObjID)/file.json", parameters: ["field_name": "FieldName", "file": Upload(fileUrl: url)], headers: ["QB-Token":realToken])
         opt.start { response in
                if response.error == nil {
    
                } else {
                     showError()
                }
         }
    } catch {
        showError()
    }