From 4ffbaffa94c66a273336e50bc6f66af185793860 Mon Sep 17 00:00:00 2001 From: Sacha DSO Date: Thu, 28 Apr 2022 11:00:32 +0200 Subject: [PATCH] Makes JSONDecoder configurable --- .../Calls/NetworkingClient+Decodable.swift | 40 +++++------ ...orkingClient+NetworkingJSONDecodable.swift | 20 +++--- Sources/Networking/NetworkingClient.swift | 58 +++++++++++++++ Sources/Networking/NetworkingParser.swift | 71 ------------------- 4 files changed, 88 insertions(+), 101 deletions(-) delete mode 100644 Sources/Networking/NetworkingParser.swift diff --git a/Sources/Networking/Calls/NetworkingClient+Decodable.swift b/Sources/Networking/Calls/NetworkingClient+Decodable.swift index ed550e9..e7548a3 100644 --- a/Sources/Networking/Calls/NetworkingClient+Decodable.swift +++ b/Sources/Networking/Calls/NetworkingClient+Decodable.swift @@ -14,7 +14,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return get(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -25,7 +25,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath return get(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -34,7 +34,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return post(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -45,7 +45,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath return post(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -54,7 +54,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return put(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -65,7 +65,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath return put(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -74,7 +74,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return patch(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -85,7 +85,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath return patch(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -94,7 +94,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return delete(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -105,7 +105,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath return delete(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -118,7 +118,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) async throws -> T { let json: Any = try await get(route, params: params) - let model:T = try NetworkingParser().toModel(json, keypath: keypath) + let model:T = try self.toModel(json, keypath: keypath) return model } @@ -127,14 +127,14 @@ public extension NetworkingClient { keypath: String? = nil) async throws -> T where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath let json: Any = try await get(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } func post(_ route: String, params: Params = Params(), keypath: String? = nil) async throws -> T { let json: Any = try await post(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } func post(_ route: String, @@ -142,14 +142,14 @@ public extension NetworkingClient { keypath: String? = nil) async throws -> T where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath let json: Any = try await post(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } func put(_ route: String, params: Params = Params(), keypath: String? = nil) async throws -> T { let json: Any = try await put(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } func put(_ route: String, @@ -157,14 +157,14 @@ public extension NetworkingClient { keypath: String? = nil) async throws -> T where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath let json: Any = try await put(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } func patch(_ route: String, params: Params = Params(), keypath: String? = nil) async throws -> T { let json: Any = try await patch(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } func patch(_ route: String, @@ -172,14 +172,14 @@ public extension NetworkingClient { keypath: String? = nil) async throws -> T where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath let json: Any = try await patch(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } func delete(_ route: String, params: Params = Params(), keypath: String? = nil) async throws -> T { let json: Any = try await delete(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } func delete(_ route: String, @@ -187,6 +187,6 @@ public extension NetworkingClient { keypath: String? = nil) async throws -> T where T: Collection { let keypath = keypath ?? defaultCollectionParsingKeyPath let json: Any = try await delete(route, params: params) - return try NetworkingParser().toModel(json, keypath: keypath) + return try self.toModel(json, keypath: keypath) } } diff --git a/Sources/Networking/Calls/NetworkingClient+NetworkingJSONDecodable.swift b/Sources/Networking/Calls/NetworkingClient+NetworkingJSONDecodable.swift index ba2cfb5..68944be 100644 --- a/Sources/Networking/Calls/NetworkingClient+NetworkingJSONDecodable.swift +++ b/Sources/Networking/Calls/NetworkingClient+NetworkingJSONDecodable.swift @@ -20,7 +20,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return get(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -31,7 +31,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher<[T], Error> { let keypath = keypath ?? defaultCollectionParsingKeyPath return get(route, params: params) - .tryMap { json -> [T] in try NetworkingParser().toModels(json, keypath: keypath) } + .tryMap { json -> [T] in try self.toModels(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -40,7 +40,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return post(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -51,7 +51,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher<[T], Error> { let keypath = keypath ?? defaultCollectionParsingKeyPath return post(route, params: params) - .tryMap { json -> [T] in try NetworkingParser().toModels(json, keypath: keypath) } + .tryMap { json -> [T] in try self.toModels(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -60,7 +60,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return put(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -72,7 +72,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher<[T], Error> { let keypath = keypath ?? defaultCollectionParsingKeyPath return put(route, params: params) - .tryMap { json -> [T] in try NetworkingParser().toModels(json, keypath: keypath) } + .tryMap { json -> [T] in try self.toModels(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -81,7 +81,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return patch(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -92,7 +92,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher<[T], Error> { let keypath = keypath ?? defaultCollectionParsingKeyPath return patch(route, params: params) - .tryMap { json -> [T] in try NetworkingParser().toModels(json, keypath: keypath) } + .tryMap { json -> [T] in try self.toModels(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -101,7 +101,7 @@ public extension NetworkingClient { params: Params = Params(), keypath: String? = nil) -> AnyPublisher { return delete(route, params: params) - .tryMap { json -> T in try NetworkingParser().toModel(json, keypath: keypath) } + .tryMap { json -> T in try self.toModel(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } @@ -112,7 +112,7 @@ public extension NetworkingClient { keypath: String? = nil) -> AnyPublisher<[T], Error> { let keypath = keypath ?? defaultCollectionParsingKeyPath return delete(route, params: params) - .tryMap { json -> [T] in try NetworkingParser().toModels(json, keypath: keypath) } + .tryMap { json -> [T] in try self.toModels(json, keypath: keypath) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } diff --git a/Sources/Networking/NetworkingClient.swift b/Sources/Networking/NetworkingClient.swift index 68c7b9a..b3c9dfb 100644 --- a/Sources/Networking/NetworkingClient.swift +++ b/Sources/Networking/NetworkingClient.swift @@ -15,6 +15,7 @@ public class NetworkingClient { public var timeout: TimeInterval? public var sessionConfiguration = URLSessionConfiguration.default public var requestRetrier: NetworkRequestRetrier? + public var jsonDecoderFactory: (() -> JSONDecoder)? /** Prints network calls to the console. @@ -32,5 +33,62 @@ public class NetworkingClient { self.baseURL = baseURL self.timeout = timeout } + + public func toModel(_ json: Any, keypath: String? = nil) throws -> T { + do { + let data = resourceData(from: json, keypath: keypath) + return try T.decode(data) + } catch (let error) { + throw error + } + } + + public func toModel(_ json: Any, keypath: String? = nil) throws -> T { + do { + let jsonObject = resourceData(from: json, keypath: keypath) + let decoder = jsonDecoderFactory?() ?? JSONDecoder() + let data = try JSONSerialization.data(withJSONObject: jsonObject, options: []) + let model = try decoder.decode(T.self, from: data) + return model + } catch (let error) { + throw error + } + } + + public func toModels(_ json: Any, keypath: String? = nil) throws -> [T] { + do { + guard let array = resourceData(from: json, keypath: keypath) as? [Any] else { + return [T]() + } + return try array.map { + try T.decode($0) + }.compactMap { $0 } + } catch (let error) { + throw error + } + } + + public func toModels(_ json: Any, keypath: String? = nil) throws -> [T] { + do { + guard let array = resourceData(from: json, keypath: keypath) as? [Any] else { + return [T]() + } + return try array.map { jsonObject in + let decoder = jsonDecoderFactory?() ?? JSONDecoder() + let data = try JSONSerialization.data(withJSONObject: jsonObject, options: []) + let model = try decoder.decode(T.self, from: data) + return model + }.compactMap { $0 } + } catch (let error) { + throw error + } + } + + private func resourceData(from json: Any, keypath: String?) -> Any { + if let keypath = keypath, !keypath.isEmpty, let dic = json as? [String: Any], let val = dic[keypath] { + return val is NSNull ? json : val + } + return json + } } diff --git a/Sources/Networking/NetworkingParser.swift b/Sources/Networking/NetworkingParser.swift deleted file mode 100644 index f7813b1..0000000 --- a/Sources/Networking/NetworkingParser.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// NetworkingParser.swift -// -// -// Created by Sacha on 13/03/2020. -// - -import Foundation - - -public struct NetworkingParser { - - public init() {} - - public func toModel(_ json: Any, keypath: String? = nil) throws -> T { - do { - let data = resourceData(from: json, keypath: keypath) - return try T.decode(data) - } catch (let error) { - throw error - } - } - - public func toModel(_ json: Any, keypath: String? = nil) throws -> T { - do { - let jsonObject = resourceData(from: json, keypath: keypath) - let decoder = JSONDecoder() - let data = try JSONSerialization.data(withJSONObject: jsonObject, options: []) - let model = try decoder.decode(T.self, from: data) - return model - } catch (let error) { - throw error - } - } - - public func toModels(_ json: Any, keypath: String? = nil) throws -> [T] { - do { - guard let array = resourceData(from: json, keypath: keypath) as? [Any] else { - return [T]() - } - return try array.map { - try T.decode($0) - }.compactMap { $0 } - } catch (let error) { - throw error - } - } - - public func toModels(_ json: Any, keypath: String? = nil) throws -> [T] { - do { - guard let array = resourceData(from: json, keypath: keypath) as? [Any] else { - return [T]() - } - return try array.map { jsonObject in - let decoder = JSONDecoder() - let data = try JSONSerialization.data(withJSONObject: jsonObject, options: []) - let model = try decoder.decode(T.self, from: data) - return model - }.compactMap { $0 } - } catch (let error) { - throw error - } - } - - private func resourceData(from json: Any, keypath: String?) -> Any { - if let keypath = keypath, !keypath.isEmpty, let dic = json as? [String: Any], let val = dic[keypath] { - return val is NSNull ? json : val - } - return json - } -}