2

I’m trying to upload an Sqlite database from IOS Swift 3 to my server using Alamofire 4.0, but having problems converting the sqlite file into the data type required to upload.

The majority of posts / question examples seem to default to uploading images, but I am struggling to find example of uploading sqlite or other file types (for back-up purposes)

I have searched for the basic code and found this so far which looks very reasonable (thanks to following post: Alamofire 4 upload with parameters)

let parameters = ["file_name": "swift_file.jpeg"]

Alamofire.upload(multipartFormData: { (multipartFormData) in
    multipartFormData.append(UIImageJPEGRepresentation(self.photoImageView.image!, 1)!, withName: "photo_path", fileName: "swift_file.jpeg", mimeType: "image/jpeg")
    for (key, value) in parameters {
        multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
    }
}, to:"http://sample.com/upload_img.php")
{ (result) in
    switch result 
    {
    case .success(let upload, _, _):
    upload.uploadProgress(closure: { (progress) in
        //Print progress
    })
    upload.responseJSON { response in
        //print response.result
    }
    case .failure(let encodingError):
    //print encodingError.description
    }
}

The part I’m struggling with is to append the sqlite file to the upload (multipartFormData.append(………..?) I’ve searched but not found any good reference posts.

Yes, i’m a newbe, but trying hard, any help would be appreciated…..

Community
  • 1
  • 1
maper1
  • 35
  • 4

1 Answers1

2

It's exactly the same as the image example except that the mime type would be application/octet-stream.

Also, you'd probably go ahead and load it directly from the fileURL rather than loading it into a Data first.

As an aside, the parameters in that example don't quite make sense, as it looks redundant with the filename provided in the upload of the image itself. So you'd use whatever parameters your web service requires, if any. If you have no additional parameters, you'd simply omit the for (key, value) { ... } loop entirely.

Finally, obviously replace the file field name with whatever field name your web service is looking for.

// any additional parameters that must be included in the request (if any)

let parameters = ["somekey": "somevalue"]

// database to be uploaded; I'm assuming it's in Documents, but perhaps you have it elsewhere, so build the URL appropriately for where the file is

let filename = "test.sqlite"
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
    .appendingPathComponent(filename)

// now initiate request

Alamofire.upload(multipartFormData: { multipartFormData in
    multipartFormData.append(fileURL, withName: "file", fileName: filename, mimeType: "application/octet-stream")

    for (key, value) in parameters {
        multipartFormData.append(value.data(using: .utf8)!, withName: key)
    }
}, to: urlString) { result in
    switch result {
    case .success(let upload, _, _):
        upload
            .authenticate(user: self.user, password: self.password)   // only needed if you're doing server authentication
            .uploadProgress { progress in
                print(progress.fractionCompleted)
            }
            .responseJSON { response in
                print("\(response.result.value)")
        }
    case .failure(let encodingError):
        print(encodingError.localizedDescription)
    }
}

Unrelated, but if you're ever unsure as to what mime type to use, you can use this routine, which will try to determine mime type from the file extension.

/// Determine mime type on the basis of extension of a file.
///
/// This requires MobileCoreServices framework.
///
/// - parameter url:  The file `URL` of the local file for which we are going to determine the mime type.
///
/// - returns:        Returns the mime type if successful. Returns application/octet-stream if unable to determine mime type.

func mimeType(for url: URL) -> String {
    let pathExtension = url.pathExtension

    if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as NSString, nil)?.takeRetainedValue() {
        if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
            return mimetype as String
        }
    }
    return "application/octet-stream";
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thanks for help, I thought everything worked fine but in my haste I read the wrong directory on the server. The file is not being uploaded.code in apple all looks good but – maper1 Dec 19 '16 at 22:04
  • This is the appropriate Alamofire code for creating a multipart request. When I do it, I see the progress and it appears on my server. I'd suspect a disconnect b/w the server code and the client code. Without seeing the server code, I'm not sure I can advise you further. – Rob Dec 19 '16 at 22:12
  • It does look like server prob, but file is working with android and was also with swiftv2 (was using SRwebclient) The "progress.fraction" completed is printing few times to value of 0.01322.... then reports "nil": I added to upload.response: .request .response .data .result .timeline Giving: Optional( { URL: http://mydomain/fileup.aspx } { status code: 500, headers { "Cache-Control" = private; Connection = close; "Content-Type" = "text/html"; "X-AspNet-Version" = "4.0.30319"; Optional(6411 bytes) FAILURE - any help? – maper1 Dec 19 '16 at 22:28
  • There's likely just some disconnect b/w what the server is expecting and how this multipart request is formed. We can't diagnose this by just looking at the response you got (though if you looked at the text of the response body, that would provide clues). Perhaps editing the question to include the Android code. Or share the server code. Or use a sniffer like Charles or Wireshark and examine what a well formed android request looked like. But there's not enough here to diagnose. – Rob Dec 19 '16 at 23:03
  • I must be doing something wrong when trying to upload a SQLite file as it is failing. However, I am successfully uploading image files and text files (changing the mimetype) with this code. Everything works fine including the parameters which are for file name and folder name. The .net ASP page deals with them exactly as expected. However, the SQLite file always fails. I found a post talking about mimetype "application/x-sqlite3" but this also failed. Any advice appreciated? thanks – maper1 Dec 21 '16 at 14:39
  • Common issues are (a) constraints put in server code re size of asset; (b) constraints put in server code re accepted file extensions or mime types. So see if any one of those three issues apply here (e.g. send image with `application/octet-stream` mime type; copy db into file with .jpg extension and try uploading that as image and see if the file is just too big; etc.). – Rob Dec 21 '16 at 16:32
  • I was in the process of clarifying server policies my supplier, but in the mean time tried every combination as suggested. the sql file was the issue not the mimetype. I added code to check file size and found it was huge.. 19meg - not sure why, but deleted and recreated, now only 100k and uploaded like a dream... Thank you @Rob for your guidance – maper1 Dec 21 '16 at 18:45
  • That makes sense. We do that so clients don't upload unreasonably large files. FYI, remember that SQLite has a [`vacuum`](http://sqlite.org/lang_vacuum.html) statement that you can use periodically (e.g. before upload) to keep file sizes reasonable. – Rob Dec 21 '16 at 19:00