Uncategorized

Easy Multipart Uploads in Swift

On several occasions I’ve worked with server devs who build endpoints for image uploading (eg user profile pictures, image posting, etc.) that expect the data in multipart format. As someone who mostly uses a thin wrapper over URLSession for my networking, this can be… frustrating. There’s no simple way to just tell URLSession that the data should be multipart encoded without pulling in something like Alamofire to my dependencies, which, when it’s just for this purpose is super annoying.

So, in collaboration with the excellent Soroush Khanlou, my mobile app development company created an encoder (like the JSONEncoder many of you will be familiar with) that will convert a Swift object to a multipart data stream that you can attach directly to a URLRequest. Suppose we wanted to upload a model like this with a multipart request:

struct TitledImageUpload: Codable {
    var title: String?
    var file: PngImage?
}

PngImage refers to an empty subclass of UIImage that exists solely so you can be explicit about how you want to encode the data – but to be clear, any UIImage can be cast to a PngImage, and if you want your data encoded as a jpg instead you can just call our extension function on UIImage called jpgImage(ofQuality:), which will return a jpg of the requested quality. And just like for a JSONEncoder, we make the model Codable.

With that definition out of the way, here’s how we use it:

let image = UIImage(named: "...")
let imageUpload = TitledImageUpload(title: "Awesome Img", file: image as PngImage)
let encoder = FormDataEncoder()
let stream = try? encoder.encode(imageUpload, boundary: "--boundary-\(Date().timeIntervalSince1970)file-image-boundary--")
let request = URLRequest(url: URL(string: "https://lithobyte.co/api/v1")!)
request.httpMethod = "POST"
request.httpBodyStream = stream?.makeInputStream()
// add headers, etc

We take the UIImage called image and create our struct from it, casting the UIImage as a PngImage, then we create a FormDataEncoder, and encode the struct with a multipart boundary. This gives us a stream that we can assign to a URLRequest‘s httpBodyStream.

This is available as a subspec in our networking library, which I introduced when talking about what I want in an ideal networking layer. To use just the multipart stuff though, add it to your Podfile like this:

pod 'FunNet/Multipart', git: 'https://github.com/LithoByte/funnet'

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s