I consider that you have already heard in regards to the well-known multipart-data add approach that everybody likes to add recordsdata and submit kind information, but when not, hopefully this text will allow you to a little bit bit to grasp this stuff higher.
Let’s begin with some idea. Don’t fret, it is only one hyperlink, in regards to the multipart/form-data content material sort specification. To shortly summarize it first I might wish to inform you a couple of phrases about how the HTTP layer works. In a nutshell, you ship some information with some headers (give it some thought as a key-value consumer information object) to a given URL utilizing a way and as a response you may get again a standing code, some headers and possibly some type of response information too. ?
- HTTP request = Technique + URL + Headers + Physique (request information)
- HTTP response = Standing code + Headers + Physique (response information)
The request methodology & URL is fairly easy, the fascinating half is once you specify the Content material-Sort
HTTP header, in our case the multipart/form-data;boundary="xxx"
worth means, that we will ship a request physique utilizing a number of elements and we will use the “xxx” boundary string as a separator between the elements. Oh, by the way in which every half can have it is personal sort and identify, we’ll use the Content material-Disposition: form-data; identify="field1"
line to let the server learn about these fields, earlier than we really ship the precise content material worth.
That is greater than sufficient idea for now, let me snow you ways we will implement all of this utilizing Swift 5. To start with, we wish to have the ability to append string values to a Information object, so we will prolong Information sort with an ‘append string utilizing encoding’ methodology:
import Basis
public extension Information {
mutating func append(
_ string: String,
encoding: String.Encoding = .utf8
) {
guard let information = string.information(utilizing: encoding) else {
return
}
append(information)
}
}
Subsequent, we want one thing that may assemble the HTTP multipart physique information, for this goal we will construct a MultipartRequest
object. We will set the boundary once we init this object and we will append the elements wanted to assemble the HTTP physique information.
The non-public strategies will assist to assemble every thing, we merely append string values to the non-public information object that holds our information construction. The general public API solely consists of two add features that you should utilize to append a key-value primarily based kind area or a complete file utilizing its information. ?
public struct MultipartRequest {
public let boundary: String
non-public let separator: String = "rn"
non-public var information: Information
public init(boundary: String = UUID().uuidString) {
self.boundary = boundary
self.information = .init()
}
non-public mutating func appendBoundarySeparator() {
information.append("--(boundary)(separator)")
}
non-public mutating func appendSeparator() {
information.append(separator)
}
non-public func disposition(_ key: String) -> String {
"Content material-Disposition: form-data; identify="(key)""
}
public mutating func add(
key: String,
worth: String
) {
appendBoundarySeparator()
information.append(disposition(key) + separator)
appendSeparator()
information.append(worth + separator)
}
public mutating func add(
key: String,
fileName: String,
fileMimeType: String,
fileData: Information
) {
appendBoundarySeparator()
information.append(disposition(key) + "; filename="(fileName)"" + separator)
information.append("Content material-Sort: (fileMimeType)" + separator + separator)
information.append(fileData)
appendSeparator()
}
public var httpContentTypeHeadeValue: String {
"multipart/form-data; boundary=(boundary)"
}
public var httpBody: Information {
var bodyData = information
bodyData.append("--(boundary)--")
return bodyData
}
}
The final remaining two public variables are helpers to simply get again the HTTP associated content material sort header worth utilizing the right boundary and the whole information object that it is best to to ship to the server. Here is how one can assemble the HTTP URLRequest utilizing the multipart struct.
var multipart = MultipartRequest()
for area in [
"firstName": "John",
"lastName": "Doe"
] {
multipart.add(key: area.key, worth: area.worth)
}
multipart.add(
key: "file",
fileName: "pic.jpg",
fileMimeType: "picture/png",
fileData: "fake-image-data".information(utilizing: .utf8)!
)
let url = URL(string: "https://httpbin.org/submit")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue(multipart.httpContentTypeHeadeValue, forHTTPHeaderField: "Content material-Sort")
request.httpBody = multipart.httpBody
let (information, response) = attempt await URLSession.shared.information(for: request)
print((response as! HTTPURLResponse).statusCode)
print(String(information: information, encoding: .utf8)!)
As you may see it is comparatively easy, you simply add the shape fields and the recordsdata that you just wish to add, and get again the HTTP associated values utilizing the helper API. I hope this text will allow you to to simulate kind submissions utilizing multipart requests with out problem. ?