Skip to content

Instantly share code, notes, and snippets.

@eugeniobaglieri
Created April 12, 2017 16:21
Show Gist options
  • Save eugeniobaglieri/dcda96b98f5b2f49ae09d3ff61ee698d to your computer and use it in GitHub Desktop.
Save eugeniobaglieri/dcda96b98f5b2f49ae09d3ff61ee698d to your computer and use it in GitHub Desktop.
//
// RequestOperation.swift
// OperationsTest
//
// Created by Eugenio Baglieri on 12/04/17.
// Copyright © 2017 Eugenio Baglieri. All rights reserved.
//
import Foundation
public class RequestOperation: Operation {
public let request: Request
public let environment: Environment
private(set) public var response: Response?
init(environment: Environment, request: Request) {
self.environment = environment
self.request = request
}
override func execute() {
do {
var urlRequest = try prepareURLRequest(for: request)
environment.headers.forEach { urlRequest.addValue($0.value as! String, forHTTPHeaderField: $0.key) }
let task = environment.session.dataTask(with: urlRequest, completionHandler: { (data, urlResponse, error) in
self.response = Response( (urlResponse as? HTTPURLResponse,data,error), for: request)
})
assert(task.state == .suspended, "Task was resumed by something other than \(self).")
task.addObserver(self, forKeyPath: "state", options: [], context: &URLSessionTaksOperationKVOContext)
task.resume()
} catch let error {
self.response = Response((nil, nil, error), for: request)
finish()
}
}
fileprivate override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard context == &URLSessionTaksOperationKVOContext else { return }
guard let _object = object as? URLSessionTask else { return }
if _object === task && keyPath == "state" && task.state == .completed {
task.removeObserver(self, forKeyPath: "state")
finish()
}
}
override func cancel() {
task.cancel()
super.cancel()
}
fileprivate class func prepareURLRequest(for request: Request) throws -> URLRequest {
// Compose the url
let fullUrl = "\(request.host)/\(request.path)"
var urlRequest = URLRequest(url: URL(string: fullUrl)!)
// Setup HTTP method
urlRequest.httpMethod = request.method.rawValue
// Add headers from request
request.headers?.forEach { urlRequest.addValue($0.value, forHTTPHeaderField: $0.key) }
// Working with parameters
if let parameters = request.parameters {
switch parameters {
case .body(let params):
// Parameters are part of the body
do {
urlRequest.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
} catch {
throw NetworkErrors.badInput
}
case .url(let params):
// Parameters are part of the url
let queryParams = params.map({ (element) -> URLQueryItem in
return URLQueryItem(name: element.key, value: element.value)
})
guard var components = URLComponents(string: fullUrl) else {
throw NetworkErrors.badInput
}
components.queryItems = queryParams
urlRequest.url = components.url
case .multipartForm(let data, let name): //Do nothing
let multipartEncoder = MultipartFormData()
multipartEncoder.append(data, withName: name)
do {
urlRequest.httpBody = try multipartEncoder.encode()
} catch {
throw NetworkErrors.badInput
}
}
}
return urlRequest
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment