forked from kudoleh/iOS-Clean-Architecture-MVVM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDataTransferService.swift
executable file
·145 lines (123 loc) · 5.07 KB
/
DataTransferService.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//
// DataTransfer.swift
// ExampleMVVM
//
// Created by Oleh Kudinov on 01.10.18.
//
import Foundation
public enum DataTransferError: Error {
case noResponse
case parsing(Error)
case networkFailure(NetworkError)
case resolvedNetworkFailure(Error)
}
public protocol DataTransferService {
typealias CompletionHandler<T> = (Result<T, DataTransferError>) -> Void
@discardableResult
func request<T: Decodable, E: ResponseRequestable>(with endpoint: E,
completion: @escaping CompletionHandler<T>) -> NetworkCancellable? where E.Response == T
@discardableResult
func request<E: ResponseRequestable>(with endpoint: E,
completion: @escaping CompletionHandler<Void>) -> NetworkCancellable? where E.Response == Void
}
public protocol DataTransferErrorResolver {
func resolve(error: NetworkError) -> Error
}
public protocol ResponseDecoder {
func decode<T: Decodable>(_ data: Data) throws -> T
}
public protocol DataTransferErrorLogger {
func log(error: Error)
}
public final class DefaultDataTransferService {
private let networkService: NetworkService
private let errorResolver: DataTransferErrorResolver
private let errorLogger: DataTransferErrorLogger
public init(with networkService: NetworkService,
errorResolver: DataTransferErrorResolver = DefaultDataTransferErrorResolver(),
errorLogger: DataTransferErrorLogger = DefaultDataTransferErrorLogger()) {
self.networkService = networkService
self.errorResolver = errorResolver
self.errorLogger = errorLogger
}
}
extension DefaultDataTransferService: DataTransferService {
public func request<T: Decodable, E: ResponseRequestable>(with endpoint: E,
completion: @escaping CompletionHandler<T>) -> NetworkCancellable? where E.Response == T {
return self.networkService.request(endpoint: endpoint) { result in
switch result {
case .success(let data):
let result: Result<T, DataTransferError> = self.decode(data: data, decoder: endpoint.responseDecoder)
DispatchQueue.main.async { return completion(result) }
case .failure(let error):
self.errorLogger.log(error: error)
let error = self.resolve(networkError: error)
DispatchQueue.main.async { return completion(.failure(error)) }
}
}
}
public func request<E>(with endpoint: E, completion: @escaping CompletionHandler<Void>) -> NetworkCancellable? where E : ResponseRequestable, E.Response == Void {
return self.networkService.request(endpoint: endpoint) { result in
switch result {
case .success:
DispatchQueue.main.async { return completion(.success(())) }
case .failure(let error):
self.errorLogger.log(error: error)
let error = self.resolve(networkError: error)
DispatchQueue.main.async { return completion(.failure(error)) }
}
}
}
// MARK: - Private
private func decode<T: Decodable>(data: Data?, decoder: ResponseDecoder) -> Result<T, DataTransferError> {
do {
guard let data = data else { return .failure(.noResponse) }
let result: T = try decoder.decode(data)
return .success(result)
} catch {
self.errorLogger.log(error: error)
return .failure(.parsing(error))
}
}
private func resolve(networkError error: NetworkError) -> DataTransferError {
let resolvedError = self.errorResolver.resolve(error: error)
return resolvedError is NetworkError ? .networkFailure(error) : .resolvedNetworkFailure(resolvedError)
}
}
// MARK: - Logger
public final class DefaultDataTransferErrorLogger: DataTransferErrorLogger {
public init() { }
public func log(error: Error) {
printIfDebug("-------------")
printIfDebug("\(error)")
}
}
// MARK: - Error Resolver
public class DefaultDataTransferErrorResolver: DataTransferErrorResolver {
public init() { }
public func resolve(error: NetworkError) -> Error {
return error
}
}
// MARK: - Response Decoders
public class JSONResponseDecoder: ResponseDecoder {
private let jsonDecoder = JSONDecoder()
public init() { }
public func decode<T: Decodable>(_ data: Data) throws -> T {
return try jsonDecoder.decode(T.self, from: data)
}
}
public class RawDataResponseDecoder: ResponseDecoder {
public init() { }
enum CodingKeys: String, CodingKey {
case `default` = ""
}
public func decode<T: Decodable>(_ data: Data) throws -> T {
if T.self is Data.Type, let data = data as? T {
return data
} else {
let context = DecodingError.Context(codingPath: [CodingKeys.default], debugDescription: "Expected Data type")
throw Swift.DecodingError.typeMismatch(T.self, context)
}
}
}