Created
April 12, 2017 16:21
-
-
Save eugeniobaglieri/dcda96b98f5b2f49ae09d3ff61ee698d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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