Created
September 3, 2017 00:02
-
-
Save OscarSwanros/1ae9fae243137e2de08318458962c3ec to your computer and use it in GitHub Desktop.
File Upload to S3 in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// UploadFileToS3Operation.swift | |
// VecinioAPIKit | |
// | |
// Created by Oscar Swanros on 9/2/17. | |
// Copyright © 2017 Vecinio Technologies Inc. All rights reserved. | |
// | |
final public class UploadFileToS3Operation: P3Operation { | |
public let image: UIImage | |
public var uploadDescriptor: S3UploadDescriptor? | |
public var uploadedFile: NetworkFile? | |
var session: URLSession? | |
private lazy var boundaryString: String = { | |
return "\(NSUUID().uuidString)" | |
}() | |
public init(image: UIImage, uploadDescriptor: S3UploadDescriptor? = nil) { | |
self.image = image | |
self.uploadDescriptor = uploadDescriptor | |
super.init() | |
addObserver(observer: P3NetworkActivityObserver()) | |
} | |
public override func execute() { | |
guard let uploadDescriptor = uploadDescriptor else { fatalError("Can't start an upload without an upload descriptor") } | |
let url = URL(string: "https://bucket.s3.amazonaws.com/") | |
var request = URLRequest(url: url!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData) | |
request.httpMethod = P3HTTPMethod.post.rawValue | |
request.setValue("multipart/form-data; boundary=\(boundaryString)", forHTTPHeaderField: "Content-Type") | |
request.httpBody = httpBody(with: uploadDescriptor.toDictionary, image: image) | |
session = URLSession(configuration: .default) | |
guard let s = session else { | |
finish(); | |
return | |
} | |
let task = s.dataTask(with: request) { (data, response, error) in | |
defer { self.finish() } | |
let decoder = JSONDecoder() | |
guard let data = data else { return } | |
do { | |
let model = try decoder.decode(P3JSONResponseWrapper<NetworkFile>.self, from: data) | |
guard let inflated = model.data else { return } | |
self.uploadedFile = inflated | |
self.finished(model: inflated) | |
} catch { | |
print(error) | |
} | |
} | |
task.resume() | |
} | |
open func finished(model: NetworkFile) { | |
// For subclassing if needed | |
} | |
private func httpBody(with params: [String:String], image: UIImage) -> Data { | |
var body = Data() | |
guard let imageData = UIImageJPEGRepresentation(image, 0.5) else { return body } | |
for (key, value) in params { | |
body.append("--\(boundaryString)\r\n") | |
body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n") | |
body.append("\(value)\r\n") | |
} | |
body.append("--\(boundaryString)\r\n") | |
body.append("Content-Disposition: form-data; name=\"file\"\r\n\r\n") | |
body.append(imageData) | |
body.append("\r\n") | |
body.append("--\(boundaryString)--\r\n") | |
return body | |
} | |
} | |
extension Data { | |
mutating func append(_ string: String) { | |
if let data = string.data(using: .utf8) { | |
append(data) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment