From f168e0de24b03e326efe01d19599eb5ebaae27a8 Mon Sep 17 00:00:00 2001 From: danvleju-rdx <163979791+danvleju-rdx@users.noreply.github.com> Date: Fri, 5 Jul 2024 09:40:20 +0300 Subject: [PATCH 1/3] wip --- .../GatewayAPIClient+Live.swift | 2 +- .../HTTPClient/HTTPClient+Interface.swift | 2 +- .../Clients/HTTPClient/HTTPClient+Live.swift | 5 +- .../Clients/HTTPClient/HTTPClient+Mock.swift | 2 +- .../NPSSurveyClient+Live.swift | 58 ++++++++----------- .../TokenPriceClient+Live.swift | 2 +- 6 files changed, 30 insertions(+), 41 deletions(-) diff --git a/RadixWallet/Clients/GatewayAPI/GatewayAPIClient/GatewayAPIClient+Live.swift b/RadixWallet/Clients/GatewayAPI/GatewayAPIClient/GatewayAPIClient+Live.swift index 1af4c174dc..f9e427a57c 100644 --- a/RadixWallet/Clients/GatewayAPI/GatewayAPIClient/GatewayAPIClient+Live.swift +++ b/RadixWallet/Clients/GatewayAPI/GatewayAPIClient/GatewayAPIClient+Live.swift @@ -70,7 +70,7 @@ extension GatewayAPIClient { urlRequest.timeoutInterval = timeoutInterval } - let data = try await httpClient.executeRequest(urlRequest) + let data = try await httpClient.executeRequest(urlRequest, nil) do { return try jsonDecoder.decode(Response.self, from: data) diff --git a/RadixWallet/Clients/HTTPClient/HTTPClient+Interface.swift b/RadixWallet/Clients/HTTPClient/HTTPClient+Interface.swift index 866a50b1a5..7ca424ac6a 100644 --- a/RadixWallet/Clients/HTTPClient/HTTPClient+Interface.swift +++ b/RadixWallet/Clients/HTTPClient/HTTPClient+Interface.swift @@ -5,5 +5,5 @@ public struct HTTPClient: Sendable, DependencyKey { // MARK: HTTPClient.ExecuteRequest extension HTTPClient { - public typealias ExecuteRequest = @Sendable (URLRequest) async throws -> Data + public typealias ExecuteRequest = @Sendable (_ request: URLRequest, _ isStatusCodeValid: ((Int) -> Bool)?) async throws -> Data } diff --git a/RadixWallet/Clients/HTTPClient/HTTPClient+Live.swift b/RadixWallet/Clients/HTTPClient/HTTPClient+Live.swift index 6dcd4b22b5..7bab9cfb53 100644 --- a/RadixWallet/Clients/HTTPClient/HTTPClient+Live.swift +++ b/RadixWallet/Clients/HTTPClient/HTTPClient+Live.swift @@ -3,14 +3,15 @@ extension HTTPClient { let session = URLSession.shared return .init( - executeRequest: { request in + executeRequest: { request, isStatusCodeValid in let (data, urlResponse) = try await session.data(for: request) guard let httpURLResponse = urlResponse as? HTTPURLResponse else { throw ExpectedHTTPURLResponse() } - guard httpURLResponse.statusCode == BadHTTPResponseCode.expected else { + let isSuccessStatusCode = isStatusCodeValid?(httpURLResponse.statusCode) ?? (httpURLResponse.statusCode == BadHTTPResponseCode.expected) + guard isSuccessStatusCode else { #if DEBUG loggerGlobal.error("Request with URL: \(request.url!.absoluteString) failed with status code: \(httpURLResponse.statusCode), data: \(data.prettyPrintedJSONString ?? "")") #endif diff --git a/RadixWallet/Clients/HTTPClient/HTTPClient+Mock.swift b/RadixWallet/Clients/HTTPClient/HTTPClient+Mock.swift index aa89236ee5..10e1b740ff 100644 --- a/RadixWallet/Clients/HTTPClient/HTTPClient+Mock.swift +++ b/RadixWallet/Clients/HTTPClient/HTTPClient+Mock.swift @@ -8,7 +8,7 @@ extension HTTPClient: TestDependencyKey { private static func noop() -> Self { .init( - executeRequest: { _ in Data() } + executeRequest: { _, _ in Data() } ) } } diff --git a/RadixWallet/Clients/NPSSurveyClient/NPSSurveyClient+Live.swift b/RadixWallet/Clients/NPSSurveyClient/NPSSurveyClient+Live.swift index cb02bc64bb..4ecec04852 100644 --- a/RadixWallet/Clients/NPSSurveyClient/NPSSurveyClient+Live.swift +++ b/RadixWallet/Clients/NPSSurveyClient/NPSSurveyClient+Live.swift @@ -70,11 +70,13 @@ extension NPSSurveyClient { extension NPSSurveyClient { #if DEBUG static let rootURL = "https://dev-wallet-net-promoter-score.radixdlt.com/v1/responses" + static let formUUID = "281622a0-dc6b-11ee-8fd1-23c96056fbd2" #else static let rootURL = "https://wallet-net-promoter-score.radixdlt.com/v1/responses" + static let formUUID = "3432b6e0-dfad-11ee-a53c-95167f067d9c" #endif - enum QueryItem: String { + enum BodyParam: String { case id case formUuid = "form_uuid" case nps @@ -101,8 +103,7 @@ extension NPSSurveyClient { } }() - var urlComponents = URLComponents(string: Self.rootURL)! - urlComponents.queryItems = [.userId(userId), .formUUID] + (feedback.map(\.queryItems) ?? []) + let urlComponents = URLComponents(string: Self.rootURL)! guard let url = urlComponents.url else { return @@ -110,42 +111,29 @@ extension NPSSurveyClient { var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "POST" + urlRequest.allHTTPHeaderFields = [ + "accept": "application/json", + "Content-Type": "application/json", + ] + + var feedbackParams: [String: Any] = [ + BodyParam.id.rawValue: userId.uuidString, + BodyParam.formUuid.rawValue: formUUID, + ] + if let feedback { + feedbackParams[BodyParam.nps.rawValue] = feedback.npsScore + } + if let reason = feedback?.reason { + feedbackParams[BodyParam.feedbackReason.rawValue] = reason + } + urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: feedbackParams) do { - _ = try await httpClient.executeRequest(urlRequest) + _ = try await httpClient.executeRequest(urlRequest) { statusCode in + [200, 202].contains(statusCode) + } } catch { loggerGlobal.info("Failed to submit nps survey feedback \(error)") } } } - -private extension URLQueryItem { - static func userId(_ id: UUID) -> Self { - .init(name: "id", value: id.uuidString) - } - - #if DEBUG - static let formUUID: Self = .init(name: "form_uuid", value: "281622a0-dc6b-11ee-8fd1-23c96056fbd2") - #else - static let formUUID: Self = .init(name: "form_uuid", value: "3432b6e0-dfad-11ee-a53c-95167f067d9c") - #endif - - static func npsScore(_ score: Int) -> Self { - .init(name: NPSSurveyClient.QueryItem.nps.rawValue, value: "\(score)") - } - - static func npsFeedbackReason(_ reason: String) -> Self { - .init(name: NPSSurveyClient.QueryItem.feedbackReason.rawValue, value: reason) - } -} - -extension NPSSurveyClient.UserFeedback { - var queryItems: [URLQueryItem] { - var queryItems: [URLQueryItem] = [] - queryItems.append(.npsScore(npsScore)) - if let reason { - queryItems.append(.npsFeedbackReason(reason)) - } - return queryItems - } -} diff --git a/RadixWallet/Clients/TokenPriceClient/TokenPriceClient+Live.swift b/RadixWallet/Clients/TokenPriceClient/TokenPriceClient+Live.swift index e9a055b434..3570a7ecf4 100644 --- a/RadixWallet/Clients/TokenPriceClient/TokenPriceClient+Live.swift +++ b/RadixWallet/Clients/TokenPriceClient/TokenPriceClient+Live.swift @@ -19,7 +19,7 @@ extension TokenPricesClient { "Content-Type": "application/json", ] - let data = try await httpClient.executeRequest(urlRequest) + let data = try await httpClient.executeRequest(urlRequest, nil) let decodedResponse = try jsonDecoder().decode(TokensPriceResponse.self, from: data) return .init(decodedResponse) } From bb924fee2266349fb82ffc15e384d2d3888db691 Mon Sep 17 00:00:00 2001 From: danvleju-rdx <163979791+danvleju-rdx@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:00:27 +0300 Subject: [PATCH 2/3] Address comments --- .../GatewayAPIClient+Live.swift | 2 +- .../HTTPClient/HTTPClient+Interface.swift | 8 +++++++- .../Clients/HTTPClient/HTTPClient+Live.swift | 5 ++--- .../NPSSurveyClient/NPSSurveyClient+Live.swift | 4 +--- .../Clients/ROLAClient/ROLAClient+Live.swift | 2 +- .../TokenPriceClient+Live.swift | 2 +- .../HTTPURLSessionResponse.swift | 17 +++++++++++++++-- 7 files changed, 28 insertions(+), 12 deletions(-) diff --git a/RadixWallet/Clients/GatewayAPI/GatewayAPIClient/GatewayAPIClient+Live.swift b/RadixWallet/Clients/GatewayAPI/GatewayAPIClient/GatewayAPIClient+Live.swift index f9e427a57c..1af4c174dc 100644 --- a/RadixWallet/Clients/GatewayAPI/GatewayAPIClient/GatewayAPIClient+Live.swift +++ b/RadixWallet/Clients/GatewayAPI/GatewayAPIClient/GatewayAPIClient+Live.swift @@ -70,7 +70,7 @@ extension GatewayAPIClient { urlRequest.timeoutInterval = timeoutInterval } - let data = try await httpClient.executeRequest(urlRequest, nil) + let data = try await httpClient.executeRequest(urlRequest) do { return try jsonDecoder.decode(Response.self, from: data) diff --git a/RadixWallet/Clients/HTTPClient/HTTPClient+Interface.swift b/RadixWallet/Clients/HTTPClient/HTTPClient+Interface.swift index 7ca424ac6a..046fd1b36a 100644 --- a/RadixWallet/Clients/HTTPClient/HTTPClient+Interface.swift +++ b/RadixWallet/Clients/HTTPClient/HTTPClient+Interface.swift @@ -5,5 +5,11 @@ public struct HTTPClient: Sendable, DependencyKey { // MARK: HTTPClient.ExecuteRequest extension HTTPClient { - public typealias ExecuteRequest = @Sendable (_ request: URLRequest, _ isStatusCodeValid: ((Int) -> Bool)?) async throws -> Data + public typealias ExecuteRequest = @Sendable (_ request: URLRequest, _ acceptedStatusCodes: [HTTPStatusCode]) async throws -> Data +} + +extension HTTPClient { + func executeRequest(_ request: URLRequest) async throws -> Data { + try await executeRequest(request, [.ok]) + } } diff --git a/RadixWallet/Clients/HTTPClient/HTTPClient+Live.swift b/RadixWallet/Clients/HTTPClient/HTTPClient+Live.swift index 7bab9cfb53..fb9e79ba01 100644 --- a/RadixWallet/Clients/HTTPClient/HTTPClient+Live.swift +++ b/RadixWallet/Clients/HTTPClient/HTTPClient+Live.swift @@ -3,15 +3,14 @@ extension HTTPClient { let session = URLSession.shared return .init( - executeRequest: { request, isStatusCodeValid in + executeRequest: { request, acceptedStatusCodes in let (data, urlResponse) = try await session.data(for: request) guard let httpURLResponse = urlResponse as? HTTPURLResponse else { throw ExpectedHTTPURLResponse() } - let isSuccessStatusCode = isStatusCodeValid?(httpURLResponse.statusCode) ?? (httpURLResponse.statusCode == BadHTTPResponseCode.expected) - guard isSuccessStatusCode else { + guard let statusCode = httpURLResponse.status, acceptedStatusCodes.contains(statusCode) else { #if DEBUG loggerGlobal.error("Request with URL: \(request.url!.absoluteString) failed with status code: \(httpURLResponse.statusCode), data: \(data.prettyPrintedJSONString ?? "")") #endif diff --git a/RadixWallet/Clients/NPSSurveyClient/NPSSurveyClient+Live.swift b/RadixWallet/Clients/NPSSurveyClient/NPSSurveyClient+Live.swift index 4ecec04852..e7dcd762e9 100644 --- a/RadixWallet/Clients/NPSSurveyClient/NPSSurveyClient+Live.swift +++ b/RadixWallet/Clients/NPSSurveyClient/NPSSurveyClient+Live.swift @@ -129,9 +129,7 @@ extension NPSSurveyClient { urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: feedbackParams) do { - _ = try await httpClient.executeRequest(urlRequest) { statusCode in - [200, 202].contains(statusCode) - } + _ = try await httpClient.executeRequest(urlRequest, [.ok, .accepted]) } catch { loggerGlobal.info("Failed to submit nps survey feedback \(error)") } diff --git a/RadixWallet/Clients/ROLAClient/ROLAClient+Live.swift b/RadixWallet/Clients/ROLAClient/ROLAClient+Live.swift index 015850bba4..df3a96b3a0 100644 --- a/RadixWallet/Clients/ROLAClient/ROLAClient+Live.swift +++ b/RadixWallet/Clients/ROLAClient/ROLAClient+Live.swift @@ -54,7 +54,7 @@ extension ROLAClient { throw ExpectedHTTPURLResponse() } - guard httpURLResponse.statusCode == BadHTTPResponseCode.expected else { + guard httpURLResponse.status == .ok else { throw BadHTTPResponseCode(got: httpURLResponse.statusCode) } diff --git a/RadixWallet/Clients/TokenPriceClient/TokenPriceClient+Live.swift b/RadixWallet/Clients/TokenPriceClient/TokenPriceClient+Live.swift index 3570a7ecf4..e9a055b434 100644 --- a/RadixWallet/Clients/TokenPriceClient/TokenPriceClient+Live.swift +++ b/RadixWallet/Clients/TokenPriceClient/TokenPriceClient+Live.swift @@ -19,7 +19,7 @@ extension TokenPricesClient { "Content-Type": "application/json", ] - let data = try await httpClient.executeRequest(urlRequest, nil) + let data = try await httpClient.executeRequest(urlRequest) let decodedResponse = try jsonDecoder().decode(TokensPriceResponse.self, from: data) return .init(decodedResponse) } diff --git a/RadixWallet/Core/SharedModels/HTTPURLSessionResponse/HTTPURLSessionResponse.swift b/RadixWallet/Core/SharedModels/HTTPURLSessionResponse/HTTPURLSessionResponse.swift index 03113ed69d..0634f4da72 100644 --- a/RadixWallet/Core/SharedModels/HTTPURLSessionResponse/HTTPURLSessionResponse.swift +++ b/RadixWallet/Core/SharedModels/HTTPURLSessionResponse/HTTPURLSessionResponse.swift @@ -6,8 +6,6 @@ public struct ExpectedHTTPURLResponse: Swift.Error { // MARK: - BadHTTPResponseCode public struct BadHTTPResponseCode: LocalizedError { public let got: Int - public let butExpected = Self.expected - public static let expected = 200 public init(got: Int) { self.got = got @@ -33,3 +31,18 @@ public struct ResponseDecodingError: Swift.Error { self.error = error } } + +// MARK: - HTTPStatusCode +public enum HTTPStatusCode: Int, Error { + /// - ok: Standard response for successful HTTP requests. + case ok = 200 + + /// - accepted: The request has been accepted for processing, but the processing has not been completed. + case accepted = 202 +} + +extension HTTPURLResponse { + var status: HTTPStatusCode? { + .init(rawValue: statusCode) + } +} From fefcd09cf3cec425cbb9d80d2371005ce8cffd21 Mon Sep 17 00:00:00 2001 From: danvleju-rdx <163979791+danvleju-rdx@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:03:20 +0300 Subject: [PATCH 3/3] Fix lint --- .../HTTPURLSessionResponse.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/RadixWallet/Core/SharedModels/HTTPURLSessionResponse/HTTPURLSessionResponse.swift b/RadixWallet/Core/SharedModels/HTTPURLSessionResponse/HTTPURLSessionResponse.swift index 0634f4da72..020ac5c450 100644 --- a/RadixWallet/Core/SharedModels/HTTPURLSessionResponse/HTTPURLSessionResponse.swift +++ b/RadixWallet/Core/SharedModels/HTTPURLSessionResponse/HTTPURLSessionResponse.swift @@ -34,11 +34,11 @@ public struct ResponseDecodingError: Swift.Error { // MARK: - HTTPStatusCode public enum HTTPStatusCode: Int, Error { - /// - ok: Standard response for successful HTTP requests. - case ok = 200 - - /// - accepted: The request has been accepted for processing, but the processing has not been completed. - case accepted = 202 + /// - ok: Standard response for successful HTTP requests. + case ok = 200 + + /// - accepted: The request has been accepted for processing, but the processing has not been completed. + case accepted = 202 } extension HTTPURLResponse {