Skip to content

Instantly share code, notes, and snippets.

@shial4
Last active November 3, 2019 23:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shial4/9bd529d82934016df49ac6e7cb0036ad to your computer and use it in GitHub Desktop.
Save shial4/9bd529d82934016df49ac6e7cb0036ad to your computer and use it in GitHub Desktop.
URLSession extension to chain operations
import Foundation
extension URLResponse {
var HTTPResponse: HTTPURLResponse? {
return self as? HTTPURLResponse
}
}

Creates a task that retrieves the contents of a URL based on the specified URL request object, and calls a handler upon completion.

Example usage:

URLSession.shared.request("https://www.example.com",
parameters: [
   "name" : "Neo",
   "surname" : "Anderson",
   "city" : "Zion"
])?
.method(.GET) // Optional, default is .GET
.body(nil) // Optional, default body is nil
.callbackSchedule(to: DispatchQueue.main) //Executes callback on main thread
.error({ (error, response) in

})
.completion({ (data, response) in

})
.resume() // Required to start the task.
import Foundation
extension URLSession {
func request(_ url: String, parameters: [String : Any]? = nil) -> URLTask? {
return task(with: url, queryItems: parameters?.map({ URLQueryItem(name: $0.key, value: String(describing:$0.value)) }))
}
private func task(with url: String, queryItems: [URLQueryItem]?) -> URLTask? {
guard let url = components(for: url, queryItems: queryItems)?.url else { return nil }
return URLTask(request: URLRequest(url: url), session: self)
}
private func components(for path: String, queryItems: [URLQueryItem]?) -> URLComponents? {
var urlComponents = URLComponents(string: path)
urlComponents?.queryItems = queryItems
return urlComponents
}
}
import Foundation
/// HTTPMethod types
public enum HTTPMethod {
case GET, POST, PUT, PATCH, DELETE, COPY, HEAD, OPTIONS, LINK, UNLINK, PURGE, LOCK, UNLOCK, PROPFIND, VIEW
}
/// A URL session task wrapper.
class URLTask {
private let session: URLSession
private var request: URLRequest
private(set) var dataTask: URLSessionDataTask!
private var completionHandler: ((Data?, URLResponse?) -> Void)? = nil
private var errorHandler: ((Error?, URLResponse?) -> Void)? = nil
private var calbackQueue: DispatchQueue?
init(request: URLRequest, session: URLSession) {
self.request = request
self.session = session
}
/// The completion handler to call when the load request is complete. This handler is executed on the main queue.
@discardableResult func completion(_ handler: @escaping (Data?, URLResponse?) -> Void) -> Self {
completionHandler = handler
return self
}
/// If the request fails, the data parameter is nil and the error parameter contain information about the failure. If a response from the server is received, regardless of whether the request completes successfully or fails, the response parameter contains that information.
@discardableResult func error(_ handler: @escaping (Error?, URLResponse?) -> Void) -> Self {
errorHandler = handler
return self
}
/// The HTTP request method. The default HTTP method is “GET”.
@discardableResult func method(_ method: HTTPMethod) -> Self {
request.httpMethod = String(describing: method)
return self
}
/// The data sent as the message body of a request, such as for an HTTP POST request.
@discardableResult func body(_ body: Data?) -> Self {
request.httpBody = body
return self
}
/// The HTTP headers sent with a request.
@discardableResult func headers(_ headers: [String:String]?) -> Self {
request.allHTTPHeaderFields = headers
return self
}
/// DispatchQueue calback to be used for delivering handlers. Use default URLSession behaviour if not specify.
@discardableResult func callbackSchedule(to: DispatchQueue?) -> Self {
calbackQueue = to
return self
}
/// Resumes the task, if it is suspended. Declaration. Newly-initialized tasks begin in a suspended state, so you need to call this method to start the task.
@discardableResult func resume() -> Self {
dataTask = session.dataTask(with: request, completionHandler: { (data, response, error) in
if let queue = self.calbackQueue {
queue.async {
self.handle(data: data, response: response, error: error)
}
} else {
self.handle(data: data, response: response, error: error)
}
})
dataTask.resume()
return self
}
private func handle(data: Data?, response: URLResponse?, error: Error?) {
guard error == nil else {
self.errorHandler?(error, response)
return
}
self.completionHandler?(data, response)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment