Skip to content

Instantly share code, notes, and snippets.

@nnsnodnb
Last active February 29, 2024 17:41
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nnsnodnb/efd4635a6be2be41fdb67135d2dd9257 to your computer and use it in GitHub Desktop.
Save nnsnodnb/efd4635a6be2be41fdb67135d2dd9257 to your computer and use it in GitHub Desktop.
How to upload jpeg image using URLSession.
import Foundation
struct AnyError: Error {
let error: Error
init(_ error: Error) {
self.error = error
}
}
import Foundation
extension Data {
var mimeType: String? {
var values = [UInt8](repeating: 0, count: 1)
copyBytes(to: &values, count: 1)
switch values[0] {
case 0xFF:
return "image/jpeg"
case 0x89:
return "image/png"
case 0x47:
return "image/gif"
case 0x49, 0x4D:
return "image/tiff"
default:
return nil
}
}
}
import UIKit
typealias HTTPHeaders = [String: String]
final class ImageUploader {
let uploadImage: UIImage
let number: Int
let boundary = "example.boundary.\(ProcessInfo.processInfo.globallyUniqueString)"
let fieldName = "upload_image"
let endpointURI: URL = .init(string: "https://example.com/uploadImage")!
var parameters: Parameters? {
return [
"number": number
]
}
var headers: HTTPHeaders {
return [
"Content-Type": "multipart/form-data; boundary=\(boundary)",
"Accept": "application/json"
]
}
init(uploadImage: UIImage, number: Int) {
self.uploadImage = uploadImage
self.number = number
}
func uploadImage(completionHandler: (ImageUploadResult) -> Void) {
let imageData = image.jpegData(compressionQuality: 1)!
let mimeType = imageData.mimeType!
var request = URLRequest(url: endpointURI, method: "POST", headers: headers)
request.httpBody = createHttpBody(binaryData: imageData, mimeType: mimeType)
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request) { (data, urlResponse, error) in
let statusCode = (urlResponse as? HTTPURLResponse)?.statusCode ?? 0
if let data = data, case (200..<300) = statusCode {
do {
let value = try Response(from: data, statusCode: statusCode)
completionHandler(.success(value))
} catch {
let _error = ResponseError(statusCode: statusCode, error: AnyError(error))
completionHandler(.failure(_error))
}
}
let tmpError = error ?? NSError(domain: "Unknown", code: 499, userInfo: nil)
let _error = ResponseError(statusCode: statusCode, error: AnyError(error))
completionHandler(.failure(_error))
}
task.resume()
}
private func createHttpBody(binaryData: Data, mimeType: String) -> Data {
var postContent = "--\(boundary)\r\n"
let fileName = "\(UUID().uuidString).jpeg"
postContent += "Content-Disposition: form-data; name=\"\(fieldName)\"; filename=\"\(fileName)\"\r\n"
postContent += "Content-Type: \(mimeType)\r\n\r\n"
var data = Data()
guard let postData = postContent.data(using: .utf8) else { return data }
data.append(postData)
data.append(binaryData)
// その他パラメータがあれば追加
if let parameters = parameters {
var content = ""
parameters.forEach {
content += "\r\n--\(boundary)\r\n"
content += "Content-Disposition: form-data; name=\"\($0.key)\"\r\n\r\n"
content += "\($0.value)"
}
if let postData = content.data(using: .utf8) { data.append(postData) }
}
// HTTPBodyの終了を設定
guard let endData = "\r\n--\(boundary)--\r\n".data(using: .utf8) else { return data }
data.append(endData)
return data
}
}
import UIKit
let url = URL(string: "https://d1f5hsy4d47upe.cloudfront.net/ac/ac6d5a8d05f5792627a8039a2bddbe79_t.jpeg")!
let data = try! Data(contentsOf: url)
let image = UIImage(data: data)!
let request = ImageUploader(uploadImage: image, number: 1)
request.uploadImage { (result) in
switch result {
case .success(let value):
assert(value.statusCode == 201)
case .failure(let error):
print(error.localizedDescription)
}
}
import Foundation
typealias ImageUploadResult = Result<Response, ResponseError>
typealias Parameters = [String: Any]
struct Response {
let statusCode: Int
let body: Parameters?
init(from data: Data, statusCode: Int) throws {
self.statusCode = statusCode
let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) as? Parameters
self.body = jsonObject
}
}
struct ResponseError: Error {
let statusCode: Int
let error: AnyError
}
extension URLRequest {
init(url: URL, method: String, headers: HTTPHeaders?) {
self.init(url: url)
httpMethod = method
if let headers = headers {
headers.forEach {
setValue($0.1, forHTTPHeaderField: $0.0)
}
}
}
}
@MavinSao
Copy link

Woww! Thanks you.

@Inqnuam
Copy link

Inqnuam commented Jan 8, 2022

Thanks!
Fixes are needed in ImageUploader.swift func uploadImage:
We should add @escaping to completionHandler
Also there's a typo, ImageUplaodResult should be ImageUploadResult

@luisggarcia
Copy link

Thanks that's what I am looking for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment