MySQL and Swift - Upload Image and File || Would It Be Better to Use Alamofire

MYSQL and Swift - Upload image and FILE || Would it be better to use Alamofire?

If you don't want to get lost in the weeds of creating complex requests, a third party library like Alamofire would be smart. It's by the same author as AFNetworking, but it's a native Swift library.

So, an Alamofire implementation might look like:

func performRequest(urlString: String, id: String, uuid: String, text: String, title: String, blogAttributedText: NSAttributedString, image: UIImage) {

let parameters = [
"id" : id,
"uuid" : uuid,
"Text" : text,
"Title" : title
]

let imageData = UIImageJPEGRepresentation(image, 0.5)!

let blogData = NSKeyedArchiver.archivedData(withRootObject: blogAttributedText)

Alamofire.upload(
multipartFormData: { multipartFormData in
for (key, value) in parameters {
if let data = value.data(using: .utf8) {
multipartFormData.append(data, withName: key)
}
}
multipartFormData.append(imageData, withName: "image", fileName: "image.jpg", mimeType: "image/jpeg")
multipartFormData.append(blogData, withName: "blog", fileName: "blog.archive", mimeType: "application/octet-stream")
},
to: urlString,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload
.validate()
.responseJSON { response in
switch response.result {
case .success(let value):
print("responseObject: \(value)")
case .failure(let responseError):
print("responseError: \(responseError)")
}
}
case .failure(let encodingError):
print("encodingError: \(encodingError)")
}
})
}

If you're going to build this request yourself, I'd suggest a few things. First, since you're sending files of different types, you might want some nice type to encapsulate this:

struct FilePayload {
let fieldname: String
let filename: String
let mimetype: String
let payload: Data
}

I'm also not sure what to make of the image/txt mime type. I'd probably use application/octet-stream for the archive.

Anyway, the building of the request could be as follows:

/// Create request.
///
/// - Parameters:
/// - url: The URL to where the post will be sent.
/// - id: The identifier of the entry
/// - uuid: The UUID of the entry
/// - text: The text.
/// - title: The title.
/// - blogAttributedText: The attributed text of the blog entry.
/// - image: The `UIImage` of the image to be included.
///
/// - Returns: The `URLRequest` that was created

func createRequest(url: URL, id: String, uuid: String, text: String, title: String, blogAttributedText: NSAttributedString, image: UIImage) -> URLRequest {
let parameters = [
"id" : id,
"uuid" : uuid,
"Text" : text, // I find it curious to see uppercase field names (I'd use lowercase for consistency's sake, but use whatever your PHP is looking for)
"Title" : title
]

let boundary = "Boundary-\(NSUUID().uuidString)"

var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept") // adjust if your response is not JSON

// use whatever field name your PHP is looking for the image; I used `image`

let imageData = UIImageJPEGRepresentation(image, 0.5)!
let imagePayload = FilePayload(fieldname: "image", filename: "image.jpg", mimetype: "image/jpeg", payload: imageData)

// again, use whatever field name your PHP is looking for the image; I used `blog`

let blogData = NSKeyedArchiver.archivedData(withRootObject: blogAttributedText)
let blogPayload = FilePayload(fieldname: "blog", filename: "blog.archive", mimetype: "application/octet-stream", payload: blogData)

request.httpBody = createBody(with: parameters, files: [imagePayload, blogPayload], boundary: boundary)

return request
}

/// Create body of the multipart/form-data request.
///
/// - Parameters:
/// - parameters: The optional dictionary containing keys and values to be passed to web service.
/// - files: The list of files to be included in the request.
/// - boundary: The `multipart/form-data` boundary
///
/// - Returns: The `Data` of the body of the request.

private func createBody(with parameters: [String: String]?, files: [FilePayload], boundary: String) -> Data {
var body = Data()

if parameters != nil {
for (key, value) in parameters! {
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.append("\(value)\r\n")
}
}

for file in files {
body.append("--\(boundary)\r\n")
body.append("Content-Disposition: form-data; name=\"\(file.fieldname)\"; filename=\"\(file.filename)\"\r\n")
body.append("Content-Type: \(file.mimetype)\r\n\r\n")
body.append(file.payload)
body.append("\r\n")
}

body.append("--\(boundary)--\r\n")
return body
}

/// Create boundary string for multipart/form-data request
///
/// - returns: The boundary string that consists of "Boundary-" followed by a UUID string.

private func generateBoundaryString() -> String {
return "Boundary-\(NSUUID().uuidString)"
}

Where

extension Data {

/// Append string to Data
///
/// Rather than littering my code with calls to `dataUsingEncoding` to convert strings to `Data`, and then add that data to the `Data`, this wraps it in a nice convenient little `Data` extension. This converts using UTF-8.
///
/// - parameter string: The string to be added to the mutable `Data`.

mutating func append(_ string: String) {
if let data = string.data(using: .utf8) {
append(data)
}
}
}

Clearly this was Swift 3 code, so I excised the NSMutableData reference.

Swift 3 Alamofire 4 Upload array of images with parameters

So the error was from the server side, that had a very small size limit for images and that's why they weren't saving. I updated the compression for the JPEG images from

if  let imageData = UIImageJPEGRepresentation(image, 1)

to

if  let imageData = UIImageJPEGRepresentation(image, 0.6)

and now it's working fine.

Thank you @Sneak for your links.

Upload multiple images in swift using Alamofire

Swift 3
Just use "[]" with image upload param to make it array of images.

Alamofire.upload(multipartFormData: { multipartFormData in
// import image to request
for imageData in imagesData {
multipartFormData.append(imageData, withName: "\(imageParamName)[]", fileName: "\(Date().timeIntervalSince1970).jpeg", mimeType: "image/jpeg")
}
for (key, value) in parameters {
multipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
}
}, to: urlString,

encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in

}
case .failure(let error):
print(error)
}

})

Alamofire: Upload Jpg to a webservice in OSX

Alamofire doesn't care at all what the bytes in the data parameter are -- it uploads them as is.

You could just as easily do something like: https://stackoverflow.com/a/17504245/3937

Note: this is not preserving the original format. An NSImage is uncompressed image data. And ... JPEG is lossy, so this will not be exactly what the image data is.

If you had an original JPEG (let's say in a file), you could create the NSData from that file instead and never create an NSImage object.

Alamorefire(Swift 3) : Ambiguous reference to member 'upload(..'

Try below code

Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(UIImageJPEGRepresentation(self.photoImageView.image!, 0.5)!, 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://server1/upload_img.php")
{ (result) in
switch result {
case .success(let upload, _, _):

upload.uploadProgress(closure: { (Progress) in
print("Upload Progress: \(Progress.fractionCompleted)")
})

upload.responseJSON { response in
//self.delegate?.showSuccessAlert()
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
// self.showSuccesAlert()
//self.removeImage("frame", fileExtension: "txt")
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}

case .failure(let encodingError):
//self.delegate?.showFailAlert()
print(encodingError)
}

}


Related Topics



Leave a reply



Submit