Skip to content

Commit 2e2f68d

Browse files
authored
Merge pull request #195 from rootstrap/improvement/issue-178-networking-layer
Improvement/issue 178 networking layer
2 parents 520f980 + 1fa7b2f commit 2e2f68d

File tree

1 file changed

+53
-59
lines changed

1 file changed

+53
-59
lines changed

ios-base/Networking/Services/BaseAPIClient.swift

Lines changed: 53 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,12 @@ internal final class BaseAPIClient: APIClient {
3838
endpoint: Endpoint,
3939
completion: @escaping CompletionCallback<T>
4040
) -> Cancellable {
41-
let apiEndpoint = APIEndpoint(endpoint: endpoint, headersProvider: headersProvider)
42-
43-
return networkProvider.request(endpoint: apiEndpoint) { [weak self] result in
41+
networkProvider.request(
42+
endpoint: buildAPIEndpoint(from: endpoint)
43+
) { [weak self] result in
4444
guard let self = self else { return }
45-
46-
switch result {
47-
case.success(let response):
48-
self.validateResult(
49-
response: response,
50-
customDecodingConfiguration: endpoint.decodingConfiguration,
51-
completion: completion
52-
)
53-
case .failure(let error):
54-
completion(.failure(error), [:])
55-
}
45+
46+
self.handle(result, for: endpoint, completion: completion)
5647
}
5748
}
5849

@@ -63,69 +54,72 @@ internal final class BaseAPIClient: APIClient {
6354
media: [MultipartMedia],
6455
completion: @escaping CompletionCallback<T>
6556
) -> Cancellable {
66-
let apiEndpoint = APIEndpoint(endpoint: endpoint, headersProvider: headersProvider)
67-
68-
return networkProvider.multipartRequest(
69-
endpoint: apiEndpoint,
57+
networkProvider.multipartRequest(
58+
endpoint: buildAPIEndpoint(from: endpoint),
7059
multipartFormKey: paramsRootKey,
7160
media: media
7261
) { [weak self] result in
7362
guard let self = self else { return }
74-
75-
switch result {
76-
case.success(let response):
77-
self.validateResult(
78-
response: response,
79-
customDecodingConfiguration: endpoint.decodingConfiguration,
80-
completion: completion
81-
)
82-
case .failure(let error):
83-
completion(.failure(error), [:])
84-
}
85-
}
86-
}
87-
88-
private func handleCustomAPIError(from response: Network.Response) -> APIError? {
89-
if response.statusCode == Network.StatusCode.unauthorized {
90-
AppDelegate.shared.unexpectedLogout()
63+
64+
self.handle(result, for: endpoint, completion: completion)
9165
}
92-
93-
return APIError(response: response, decodingConfiguration: decodingConfiguration)
9466
}
9567

96-
private func validateResult<T: Decodable>(
97-
response: Network.Response,
98-
customDecodingConfiguration: DecodingConfiguration?,
68+
private func handle<T: Decodable>(
69+
_ result: Result<Network.Response, Error>,
70+
for endpoint: Endpoint,
9971
completion: CompletionCallback<T>
10072
) {
101-
let responseData = response.data
102-
103-
guard let data = responseData, !data.isEmpty else {
104-
if emptyDataStatusCodes.contains(response.statusCode) {
105-
completion(.success(.none), response.headers)
106-
} else {
107-
let emptyResponseInvalidError = App.error(
108-
domain: .network,
109-
localizedDescription: "Unexpected empty response".localized
110-
)
111-
completion(.failure(emptyResponseInvalidError), response.headers)
112-
}
113-
114-
return
73+
switch result {
74+
case .success(let response): handle(response, with: endpoint.decodingConfiguration, completion: completion)
75+
case .failure(let error): completion(.failure(error), [:])
11576
}
116-
117-
let decoder = JSONDecoder(
118-
decodingConfig: customDecodingConfiguration ?? decodingConfiguration
77+
}
78+
79+
private func buildAPIEndpoint(from endpoint: Endpoint) -> APIEndpoint {
80+
APIEndpoint(endpoint: endpoint, headersProvider: headersProvider)
81+
}
82+
83+
private var unexpectedResponseError: NSError {
84+
App.error(
85+
domain: .network,
86+
localizedDescription: "Unexpected empty response".localized
11987
)
88+
}
89+
90+
private func handle<T: Decodable>(
91+
_ response: Network.Response,
92+
with configuration: DecodingConfiguration?,
93+
completion: CompletionCallback<T>
94+
) {
12095
do {
121-
let decodedObject = try decoder.decode(T.self, from: data)
96+
guard let data = response.data, !data.isEmpty else {
97+
guard emptyDataStatusCodes.contains(response.statusCode) else { throw unexpectedResponseError }
98+
99+
return completion(.success(.none), response.headers)
100+
}
122101

123-
completion(.success(decodedObject), response.headers)
102+
completion(.success(try decode(data, with: configuration)), response.headers)
124103
} catch let error {
125104
completion(
126105
.failure(handleCustomAPIError(from: response) ?? error),
127106
response.headers
128107
)
129108
}
130109
}
110+
111+
private func decode<M: Decodable>(_ data: Data, with configuration: DecodingConfiguration?) throws -> M {
112+
let decoder = JSONDecoder(decodingConfig: configuration ?? decodingConfiguration)
113+
114+
return try decoder.decode(M.self, from: data)
115+
}
116+
117+
private func handleCustomAPIError(from response: Network.Response) -> APIError? {
118+
if response.statusCode == Network.StatusCode.unauthorized {
119+
AppDelegate.shared.unexpectedLogout()
120+
}
121+
122+
return APIError(response: response, decodingConfiguration: decodingConfiguration)
123+
}
124+
131125
}

0 commit comments

Comments
 (0)