Last active
April 28, 2020 23:17
-
-
Save igorcferreira/7b51ce184ebb8f9bf2872d404323bd62 to your computer and use it in GitHub Desktop.
An experiment of how to use Combine+URLRequest.
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
import Foundation | |
import Combine | |
import PlaygroundSupport | |
func request<Failure: Error, Output: Publisher>(url: URLRequest, | |
session: URLSession = .shared, | |
queue: DispatchQueue = .main, | |
parser: @escaping (Data) -> Output, | |
parseError: @escaping (Error) -> Failure, | |
completion: @escaping (Result<Output.Output, Failure>) -> Void) -> AnyCancellable { | |
return session.dataTaskPublisher(for: url) | |
.tryMap({ (output) -> Data in | |
if let httpResponse = output.response as? HTTPURLResponse, !(200..<300).contains(httpResponse.statusCode) { | |
throw URLError(URLError.Code(rawValue: httpResponse.statusCode)) | |
} else { | |
return output.data | |
} | |
}) | |
.mapError(parseError) | |
.first() | |
.flatMap({ parser($0).mapError(parseError) }) | |
.receive(on: queue) | |
.sink(receiveCompletion: { (result) in | |
if case .failure(let error) = result { | |
completion(.failure(error)) | |
} | |
}, receiveValue: { (response) in | |
completion(.success(response)) | |
}) | |
} | |
/// This extension allows a Rx Data parser | |
extension String { | |
enum StringParseError: Error { | |
case invalidString | |
} | |
static func parsePublisher(from data: Data) -> AnyPublisher<String, StringParseError> { | |
return String.parsePublisher(from: data, encoding: .utf8) | |
} | |
static func parsePublisher(from data: Data, encoding: Encoding) -> AnyPublisher<String, StringParseError> { | |
if let output = String(data: data, encoding: encoding) { | |
return Just(output) | |
.mapError({ _ in StringParseError.invalidString }) //This mapError is here only to have a single return type | |
.eraseToAnyPublisher() | |
} else { | |
return Fail(error: StringParseError.invalidString) | |
.eraseToAnyPublisher() | |
} | |
} | |
} | |
let url = URLRequest(url: URL(string: "https://igorcferreira.dev/")!) | |
let cancellable = request(url: url, | |
parser: String.parsePublisher(from:), | |
parseError: { $0 }, | |
completion: { (result: Result<String, Error>) in | |
dump(result) | |
PlaygroundPage.current.finishExecution() | |
}) | |
PlaygroundPage.current.needsIndefiniteExecution = true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment