- Hands-On Design Patterns with Swift
- Florent Vilmart Giordano Scalzo Sergio De Simone
- 351字
- 2021-07-02 14:45:13
Sending requests with Encodable
The counterpart to Decodable is Encodable; an object that conforms to both Encodable and Decodable is Codable. Now that you have seen how to download data from a server and parse it into a pure Swift object, you'll probably want to send data to the server from pure Swift objects:
func post<T, U>(url: URL, body: U, callback: @escaping (T?, Error?) -> Void) throws
-> URLSessionTask where T: Decodable, U: Encodable {
var request = URLRequest(url: url)
request.httpBody = try JSONEncoder().encode(body)
request.httpMethod = "POST"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
// Exact same code as in the get<T> callback, extracted
handleResponse(data: data,
response: response,
error: error,
callback: callback)
}
task.resume()
return task
}
As you can see, we have now minimally changed the implementation of the original get<T>. That begs for a higher level of abstraction on both URLSession and URLRequest:
- We can make the URLRequest class aware of the body parsing logic, as follows:
extension URLRequest {
enum HTTPMethod: String {
case GET
case POST
case PUT
case DELETE
}
init<T>(url: URL, method: HTTPMethod, body: T?) throws where T: Encodable {
self.init(url: url)
httpMethod = method.rawValue
if let body = body {
httpBody = try JSONEncoder().encode(body)
}
}
}
- Let's update URLSession with the response parsing logic, over the dataTask call:
extension URLSession {
func dataTask<T>(with request: URLRequest,
callback: @escaping (T?, Error?) -> Void)
throws -> URLSessionTask where T: Decodable {
return URLSession.shared.dataTask(with: request) { data, response, error in
handleResponse(data: data,
response: response,
error: error,
callback: callback)
}
}
}
- With those abstractions done, we can finally use our enhanced URLSession all over our program. Let's start with the new URLRequest:
let request = try! URLRequest(url: URL(string: "http://example.com")!,
method: .POST,
body: MyBody())
- We can then get URLSessionDataTask from URLSession:
let task = try? URLSession.shared.dataTask(with: request) { (result: MyResult?, error) in
// Handle result / error
}
task?.resume()
You now have the basic building blocks required to build a type-safe and powerful network client. You'll be able to reuse these patterns across your programs, as they are very generic.