@@ -2,122 +2,112 @@ import Foundation
2
2
3
3
extension Networking {
4
4
func handle< T: Decodable > ( _ requestType: RequestType , path: String , parameters: Any ? ) async -> Result < T , NetworkingError > {
5
- var data : Data ?
6
5
do {
7
6
logger. info ( " Starting \( requestType. rawValue) request to \( path, privacy: . public) " )
8
7
9
8
if let fakeRequest = try FakeRequest . find ( ofType: requestType, forPath: path, in: fakeRequests) {
10
- let ( _, response, error) = try handleFakeRequest ( fakeRequest, path: path, cacheName: nil , cachingLevel: . none)
11
- if fakeRequest. delay > 0 {
12
- let nanoseconds = UInt64 ( fakeRequest. delay * 1_000_000_000 )
13
- try ? await Task . sleep ( nanoseconds: nanoseconds)
14
- }
15
- let result = try JSONResult ( body: fakeRequest. response, response: response, error: error)
16
- switch result {
17
- case . success( let response) :
18
- if T . self == Data . self {
19
- logger. info ( " Successfully processed fake request to \( path, privacy: . public) " )
20
- return . success( Data ( ) as! T )
21
- } else if T . self == NetworkingResponse . self {
22
- let headers = Dictionary ( uniqueKeysWithValues: response. headers. compactMap { key, value in
23
- ( key as? String ) . map { ( $0, AnyCodable ( value) ) }
24
- } )
25
- let body = try JSONDecoder ( ) . decode ( [ String : AnyCodable ] . self, from: response. data)
26
- let networkingJSON = NetworkingResponse ( headers: headers, body: body)
27
- return . success( networkingJSON as! T )
28
- } else {
29
- let decoder = JSONDecoder ( )
30
- decoder. dateDecodingStrategy = . iso8601
31
- let decodedResponse = try decoder. decode ( T . self, from: response. data)
32
- logger. info ( " Successfully decoded response from fake request to \( path, privacy: . public) " )
33
- return . success( decodedResponse)
34
- }
35
- case . failure( let response) :
36
- logger. error ( " Failed to process fake request to \( path, privacy: . public) : \( response. error. localizedDescription, privacy: . public) " )
37
- return . failure( . unexpectedError( statusCode: nil , message: " Failed to process fake request (error: \( response. error. localizedDescription) ). " ) )
38
- }
9
+ return try await handleFakeRequest ( fakeRequest, path: path, requestType: requestType)
39
10
}
40
11
41
- let parameterType : Networking . ParameterType ? = parameters != nil ? . json : nil
42
- var request = URLRequest ( url: try composedURL ( with: path) , requestType: requestType, path: path, parameterType: parameterType, responseType: . json, boundary: boundary, authorizationHeaderValue: authorizationHeaderValue, token: token, authorizationHeaderKey: authorizationHeaderKey, headerFields: headerFields)
12
+ let request = try createRequest ( path: path, requestType: requestType, parameters: parameters)
13
+ let ( responseData, response) = try await session. data ( for: request)
14
+ return try handleResponse ( responseData: responseData, response: response, path: path)
43
15
44
- if let parameters = parameters {
45
- request. httpBody = try JSONSerialization . data ( withJSONObject: parameters, options: [ ] )
46
- }
16
+ } catch {
17
+ return handleRequestError ( error: error)
18
+ }
19
+ }
47
20
48
- let ( responseData, response) = try await session. data ( for: request)
49
- data = responseData
50
- guard let httpResponse = response as? HTTPURLResponse else {
51
- logger. error ( " Invalid response received from \( path, privacy: . public) " )
52
- return . failure( . invalidResponse)
53
- }
21
+ private func handleFakeRequest< T: Decodable > ( _ fakeRequest: FakeRequest , path: String , requestType: RequestType ) async throws -> Result < T , NetworkingError > {
22
+ let ( _, response, error) = try handleFakeRequest ( fakeRequest, path: path, cacheName: nil , cachingLevel: . none)
54
23
55
- let statusCode = httpResponse. statusCode
56
- switch statusCode. statusCodeType {
57
- case . informational, . successful:
58
- logger. info ( " Received successful response with status code \( statusCode) from \( path, privacy: . public) " )
59
- if T . self == Data . self {
60
- return . success( Data ( ) as! T )
61
- } else if T . self == NetworkingResponse . self {
62
- let headers = Dictionary ( uniqueKeysWithValues: httpResponse. allHeaderFields. compactMap { key, value in
63
- ( key as? String ) . map { ( $0, AnyCodable ( value) ) }
64
- } )
65
- let body = try JSONDecoder ( ) . decode ( [ String : AnyCodable ] . self, from: responseData)
66
- let networkingJSON = NetworkingResponse ( headers: headers, body: body)
67
- return . success( networkingJSON as! T )
68
- } else {
69
- let decoder = JSONDecoder ( )
70
- decoder. dateDecodingStrategy = . iso8601
71
- let decodedResponse = try decoder. decode ( T . self, from: responseData)
72
- return . success( decodedResponse)
73
- }
74
- case . redirection:
75
- logger. warning ( " Redirection response with status code \( statusCode) from \( path, privacy: . public) " )
76
- return . failure( . unexpectedError( statusCode: statusCode, message: " Redirection occurred. " ) )
77
- case . clientError:
78
- let errorMessage = HTTPURLResponse . localizedString ( forStatusCode: statusCode)
79
- if let jsonString = String ( data: responseData, encoding: . utf8) {
80
- logger. warning ( " Client error: \( jsonString, privacy: . public) with status code \( statusCode) from \( path, privacy: . public) " )
81
- }
82
- if let errorResponse = try ? JSONDecoder ( ) . decode ( ErrorResponse . self, from: responseData) {
83
- logger. warning ( " Client error: \( errorResponse. combinedMessage, privacy: . public) with status code \( statusCode) from \( path, privacy: . public) " )
84
- return . failure( . clientError( statusCode: statusCode, message: errorResponse. combinedMessage) )
85
- } else {
86
- logger. warning ( " Client error: \( errorMessage, privacy: . public) with status code \( statusCode) from \( path, privacy: . public) " )
87
- return . failure( . clientError( statusCode: statusCode, message: errorMessage) )
88
- }
89
- case . serverError:
90
- let errorMessage = HTTPURLResponse . localizedString ( forStatusCode: statusCode)
91
- var errorDetails : [ String : Any ] ? = nil
92
- if let jsonString = String ( data: responseData, encoding: . utf8) {
93
- logger. error ( " Server error: \( jsonString, privacy: . public) with status code \( statusCode) from \( path, privacy: . public) " )
94
- }
95
- if let errorResponse = try ? JSONDecoder ( ) . decode ( ErrorResponse . self, from: responseData) {
96
- errorDetails = [ " error " : errorResponse. error ?? " " ,
97
- " message " : errorResponse. message ?? " " ,
98
- " errors " : errorResponse. errors ?? [ : ] ]
99
- logger. error ( " Server error: \( errorResponse. combinedMessage, privacy: . public) with status code \( statusCode) from \( path, privacy: . public) " )
100
- return . failure( . serverError( statusCode: statusCode, message: errorResponse. combinedMessage, details: errorDetails) )
101
- } else {
102
- logger. error ( " Server error: \( errorMessage, privacy: . public) with status code \( statusCode) from \( path, privacy: . public) " )
103
- return . failure( . serverError( statusCode: statusCode, message: errorMessage, details: errorDetails) )
104
- }
105
- case . cancelled:
106
- logger. info ( " Request cancelled with status code \( statusCode) from \( path, privacy: . public) " )
107
- return . failure( . unexpectedError( statusCode: statusCode, message: " Request was cancelled. " ) )
108
- case . unknown:
109
- logger. error ( " Unexpected error with status code \( statusCode) from \( path, privacy: . public) " )
110
- return . failure( . unexpectedError( statusCode: statusCode, message: " An unexpected error occurred. " ) )
111
- }
112
- } catch let error as NSError {
113
- if let data = data, let jsonString = String ( data: data, encoding: . utf8) {
114
- logger. error ( " Unexpected error occurred: \( error. localizedDescription, privacy: . public) . Response data: \( jsonString, privacy: . public) " )
115
- } else if let decodingError = error as? DecodingError {
116
- logger. error ( " Unexpected error occurred: \( decodingError. detailedMessage, privacy: . public) " )
117
- } else {
118
- logger. error ( " Unexpected error occurred: \( error. localizedDescription, privacy: . public) " )
119
- }
120
- return . failure( . unexpectedError( statusCode: nil , message: " Failed to process request (error: \( error. localizedDescription) ). " ) )
24
+ if fakeRequest. delay > 0 {
25
+ try ? await Task . sleep ( nanoseconds: UInt64 ( fakeRequest. delay * 1_000_000_000 ) )
26
+ }
27
+
28
+ let result = try JSONResult ( body: fakeRequest. response, response: response, error: error)
29
+ return try handleResponse ( responseData: result. data, response: response, path: path)
30
+ }
31
+
32
+ private func createRequest( path: String , requestType: RequestType , parameters: Any ? ) throws -> URLRequest {
33
+ let parameterType : Networking . ParameterType ? = parameters != nil ? . json : nil
34
+ var request = URLRequest ( url: try composedURL ( with: path) , requestType: requestType, path: path, parameterType: parameterType, responseType: . json, boundary: boundary, authorizationHeaderValue: authorizationHeaderValue, token: token, authorizationHeaderKey: authorizationHeaderKey, headerFields: headerFields)
35
+
36
+ if let parameters = parameters {
37
+ request. httpBody = try JSONSerialization . data ( withJSONObject: parameters, options: [ ] )
38
+ }
39
+
40
+ return request
41
+ }
42
+
43
+ private func handleResponse< T: Decodable > ( responseData: Data , response: URLResponse , path: String ) throws -> Result < T , NetworkingError > {
44
+ guard let httpResponse = response as? HTTPURLResponse else {
45
+ return . failure( . invalidResponse)
46
+ }
47
+
48
+ let statusCode = httpResponse. statusCode
49
+ switch statusCode. statusCodeType {
50
+ case . informational, . successful:
51
+ return try handleSuccessfulResponse ( responseData: responseData, path: path, httpResponse: httpResponse)
52
+ case . redirection:
53
+ return . failure( . unexpectedError( statusCode: statusCode, message: " Redirection occurred. " ) )
54
+ case . clientError:
55
+ return try handleClientError ( responseData: responseData, statusCode: statusCode, path: path)
56
+ case . serverError:
57
+ return try handleServerError ( responseData: responseData, statusCode: statusCode, path: path)
58
+ case . cancelled:
59
+ return . failure( . unexpectedError( statusCode: statusCode, message: " Request was cancelled. " ) )
60
+ case . unknown:
61
+ return . failure( . unexpectedError( statusCode: statusCode, message: " An unexpected error occurred. " ) )
62
+ }
63
+ }
64
+
65
+ private func handleSuccessfulResponse< T: Decodable > ( responseData: Data , path: String , httpResponse: HTTPURLResponse ) throws -> Result < T , NetworkingError > {
66
+ if T . self == Data . self {
67
+ return . success( Data ( ) as! T )
68
+ } else if T . self == NetworkingResponse . self {
69
+ let headers = Dictionary ( uniqueKeysWithValues: httpResponse. allHeaderFields. compactMap { key, value in
70
+ ( key as? String ) . map { ( $0, AnyCodable ( value) ) }
71
+ } )
72
+ let body = try JSONDecoder ( ) . decode ( [ String : AnyCodable ] . self, from: responseData)
73
+ let networkingJSON = NetworkingResponse ( headers: headers, body: body)
74
+ return . success( networkingJSON as! T )
75
+ } else {
76
+ let decoder = JSONDecoder ( )
77
+ decoder. dateDecodingStrategy = . iso8601
78
+ let decodedResponse = try decoder. decode ( T . self, from: responseData)
79
+ return . success( decodedResponse)
80
+ }
81
+ }
82
+
83
+ private func handleClientError< T: Decodable > ( responseData: Data , statusCode: Int , path: String ) throws -> Result < T , NetworkingError > {
84
+ let errorMessage = HTTPURLResponse . localizedString ( forStatusCode: statusCode)
85
+ if let errorResponse = try ? JSONDecoder ( ) . decode ( ErrorResponse . self, from: responseData) {
86
+ return . failure( . clientError( statusCode: statusCode, message: errorResponse. combinedMessage) )
87
+ } else {
88
+ return . failure( . clientError( statusCode: statusCode, message: errorMessage) )
89
+ }
90
+ }
91
+
92
+ private func handleServerError< T: Decodable > ( responseData: Data , statusCode: Int , path: String ) throws -> Result < T , NetworkingError > {
93
+ let errorMessage = HTTPURLResponse . localizedString ( forStatusCode: statusCode)
94
+ var errorDetails : [ String : Any ] ? = nil
95
+ if let errorResponse = try ? JSONDecoder ( ) . decode ( ErrorResponse . self, from: responseData) {
96
+ errorDetails = [ " error " : errorResponse. error ?? " " ,
97
+ " message " : errorResponse. message ?? " " ,
98
+ " errors " : errorResponse. errors ?? [ : ] ]
99
+ return . failure( . serverError( statusCode: statusCode, message: errorResponse. combinedMessage, details: errorDetails) )
100
+ } else {
101
+ return . failure( . serverError( statusCode: statusCode, message: errorMessage, details: errorDetails) )
102
+ }
103
+ }
104
+
105
+ private func handleRequestError< T: Decodable > ( error: Error ) -> Result < T , NetworkingError > {
106
+ if let decodingError = error as? DecodingError {
107
+ logger. error ( " Unexpected error occurred: \( decodingError. detailedMessage, privacy: . public) " )
108
+ } else {
109
+ logger. error ( " Unexpected error occurred: \( error. localizedDescription, privacy: . public) " )
121
110
}
111
+ return . failure( . unexpectedError( statusCode: nil , message: " Failed to process request (error: \( error. localizedDescription) ). " ) )
122
112
}
123
113
}
0 commit comments