You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

57 lines
1.7 KiB

import SwiftUI
import Combine
enum URLSessionError: Error {
case invalidResponse
case serverErrorMessage(statusCode: Int, data: Data)
case urlError(URLError)
}
extension URLSession {
func send(request: URLRequest) -> AnyPublisher<Data, URLSessionError> {
dataTaskPublisher(for: request)
.mapError { URLSessionError.urlError($0) }
.flatMap { data, response -> AnyPublisher<Data, URLSessionError> in
guard let response = response as? HTTPURLResponse else {
return .fail(.invalidResponse)
}
guard 200..<300 ~= response.statusCode else {
return .fail(.serverErrorMessage(statusCode: response.statusCode,
data: data))
}
return .just(data)
}.eraseToAnyPublisher()
}
}
extension JSONDecoder: TopLevelDecoder {}
extension Publisher {
/// - seealso: https://twitter.com/peres/status/1136132104020881408
func flatMapLatest<T: Publisher>(_ transform: @escaping (Self.Output) -> T) -> Publishers.SwitchToLatest<T, Publishers.Map<Self, T>> where T.Failure == Self.Failure {
map(transform).switchToLatest()
}
}
extension Publisher {
static func empty() -> AnyPublisher<Output, Failure> {
return Empty()
.eraseToAnyPublisher()
}
static func just(_ output: Output) -> AnyPublisher<Output, Failure> {
return Just(output)
.catch { _ in AnyPublisher<Output, Failure>.empty() }
.eraseToAnyPublisher()
}
static func fail(_ error: Failure) -> AnyPublisher<Output, Failure> {
return Fail(error: error)
.eraseToAnyPublisher()
}
}