Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@igorcferreira
Last active April 28, 2020 23:17
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 igorcferreira/7b51ce184ebb8f9bf2872d404323bd62 to your computer and use it in GitHub Desktop.
Save igorcferreira/7b51ce184ebb8f9bf2872d404323bd62 to your computer and use it in GitHub Desktop.
An experiment of how to use Combine+URLRequest.
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