Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overridden parameter types on GET/DELETE #264

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Allow overridden parameter types on GET/DELETE

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Fri Aug 6 10:54:16 2021 +0800
#
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 1 and 1 different commits each, respectively.
# (use "git pull" to merge the remote branch into yours)
#
# Changes to be committed:
# modified: Sources/Networking+HTTPRequests.swift
#
# Untracked files:
# .idea/
#
18 changes: 18 additions & 0 deletions Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@
44DFD3B01D9A34540014E9F2 /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 148341701CF1CF0500E91F01 /* Image.swift */; };
44DFD3B11D9A3FC80014E9F2 /* pig.png in Resources */ = {isa = PBXBuildFile; fileRef = 14B0CEE31CF1D0D700049AD6 /* pig.png */; };
44DFD3B21D9A3FC90014E9F2 /* pig.png in Resources */ = {isa = PBXBuildFile; fileRef = 14B0CEE31CF1D0D700049AD6 /* pig.png */; };
BA79824C3FD10818DA976F8A /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */; };
BA7985EE02F8B15CAE1C86DD /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */; };
BA79866331D2E147C9A9EE21 /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */; };
BA79878BCE133FA5429E6DAA /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */; };
BA798837CAF824FACE6DDC91 /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */; };
BA7988926836681D75A2D44C /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */; };
BA798D222B6284F771465C87 /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */; };
BA798DDD639F9AAFCF98EF39 /* ErrorLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */; };
E6ED61311E27CD630058ACE9 /* UnauthorizedCallbackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6ED61301E27CD630058ACE9 /* UnauthorizedCallbackTests.swift */; };
E6ED61321E27CD630058ACE9 /* UnauthorizedCallbackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6ED61301E27CD630058ACE9 /* UnauthorizedCallbackTests.swift */; };
E6ED61331E27CD630058ACE9 /* UnauthorizedCallbackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6ED61301E27CD630058ACE9 /* UnauthorizedCallbackTests.swift */; };
Expand Down Expand Up @@ -247,6 +255,7 @@
44DFD39B1D9A2D5A0014E9F2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
44DFD39F1D9A2EA70014E9F2 /* CellData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellData.swift; sourceTree = "<group>"; };
44DFD3A11D9A33610014E9F2 /* FakeImageController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FakeImageController.swift; sourceTree = "<group>"; };
BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorLogger.swift; sourceTree = "<group>"; };
E6ED61301E27CD630058ACE9 /* UnauthorizedCallbackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnauthorizedCallbackTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -380,6 +389,7 @@
4488DBC01D9BBFCF007D7A14 /* FakeRequest.swift */,
1474C1C21CA2988900E15D84 /* TestCheck.swift */,
446C24621DFEE964006FA6CC /* Helpers.swift */,
BA7983C1B85B8AE9BAF59E3E /* ErrorLogger.swift */,
);
path = Sources;
sourceTree = "<group>";
Expand Down Expand Up @@ -815,6 +825,7 @@
1413F4771CE7968E00482096 /* JSON.swift in Sources */,
4488DBCC1D9BCA0E007D7A14 /* FakeRequestTests.swift in Sources */,
445F053321007512003906C2 /* NetworkingTests.swift in Sources */,
BA798837CAF824FACE6DDC91 /* ErrorLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -834,6 +845,7 @@
14638D0A1CC64629002B9433 /* Networking.swift in Sources */,
4488DBC51D9BBFCF007D7A14 /* FakeRequest.swift in Sources */,
14638D0B1CC64629002B9433 /* TestCheck.swift in Sources */,
BA7985EE02F8B15CAE1C86DD /* ErrorLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -853,6 +865,7 @@
14638D201CC64733002B9433 /* Networking.swift in Sources */,
4488DBC61D9BBFCF007D7A14 /* FakeRequest.swift in Sources */,
14638D211CC64733002B9433 /* TestCheck.swift in Sources */,
BA79866331D2E147C9A9EE21 /* ErrorLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -872,6 +885,7 @@
14638D361CC647B8002B9433 /* Networking.swift in Sources */,
4488DBC71D9BBFCF007D7A14 /* FakeRequest.swift in Sources */,
14638D371CC647B8002B9433 /* TestCheck.swift in Sources */,
BA798D222B6284F771465C87 /* ErrorLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -891,6 +905,7 @@
14638D4C1CC64829002B9433 /* Networking.swift in Sources */,
4488DBC81D9BBFCF007D7A14 /* FakeRequest.swift in Sources */,
14638D4D1CC64829002B9433 /* TestCheck.swift in Sources */,
BA79878BCE133FA5429E6DAA /* ErrorLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -926,6 +941,7 @@
1474C1C81CA2988900E15D84 /* Networking.swift in Sources */,
4488DBCA1D9BCA0E007D7A14 /* FakeRequestTests.swift in Sources */,
445F053121007512003906C2 /* NetworkingTests.swift in Sources */,
BA7988926836681D75A2D44C /* ErrorLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -961,6 +977,7 @@
44B5D3A01D19B9E5004378B9 /* Networking.swift in Sources */,
4488DBCB1D9BCA0E007D7A14 /* FakeRequestTests.swift in Sources */,
445F053221007512003906C2 /* NetworkingTests.swift in Sources */,
BA79824C3FD10818DA976F8A /* ErrorLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -984,6 +1001,7 @@
446C24631DFEE964006FA6CC /* Helpers.swift in Sources */,
44DFD3A01D9A2EA70014E9F2 /* CellData.swift in Sources */,
44A6D5481E4122DE00405A7E /* Networking+Private.swift in Sources */,
BA798DDD639F9AAFCF98EF39 /* ErrorLogger.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
44 changes: 44 additions & 0 deletions Sources/ErrorLogger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
////////////////////////////////////////////////////////////////////////////////
//
// SYMBIOSE
// Copyright 2020 Symbiose Inc
// All Rights Reserved.
//
// NOTICE: This software is proprietary information.
// Unauthorized use is prohibited.
//
////////////////////////////////////////////////////////////////////////////////

import Foundation

public protocol ErrorLoggerProvider {

func provide(error: Error?) -> ErrorLogger

}

public class ConsoleLogProvider: ErrorLoggerProvider {

public func provide(error: Error?) -> ErrorLogger {
ConsoleErrorLogger()
}

}

public protocol ErrorLogger {

func log(_ message: String)

func flush()

}

class ConsoleErrorLogger: ErrorLogger {

func log(_ message: String) {
print(message)
}

func flush() {} // Not required for console logger

}
30 changes: 30 additions & 0 deletions Sources/Networking+HTTPRequests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ public extension Networking {
return handleJSONRequest(.get, path: path, cacheName: nil, parameterType: parameterType, parameters: parameters, responseType: .json, cachingLevel: cachingLevel, completion: completion)
}

/// GET request to the specified path, allowing overridden parameter types
///
/// Overridden parameter types can be useful, for example some REST-ful APIs do not strictly adhere to spec.
///
/// - Parameters:
/// - path: The path for the GET request.
/// - parameterType: The parameters type to be used.
/// - parameters: The parameters to be used, they will be serialized using Percent-encoding and appended to the URL.
/// - completion: The result of the operation, it's an enum with two cases: success and failure.
/// - Returns: The request identifier.
@discardableResult
func get(_ path: String, parameterType: ParameterType, parameters: Any? = nil, completion: @escaping (_ result: JSONResult) -> Void) -> String {
handleJSONRequest(.get, path: path, cacheName: nil, parameterType: parameterType, parameters: parameters, responseType: .json, cachingLevel: .none, completion: completion)
}

/// Registers a fake GET request for the specified path. After registering this, every GET request to the path, will return the registered response.
///
/// - Parameters:
Expand Down Expand Up @@ -205,6 +220,21 @@ public extension Networking {
return handleJSONRequest(.delete, path: path, cacheName: nil, parameterType: parameterType, parameters: parameters, responseType: .json, cachingLevel: .none, completion: completion)
}

/// DELETE request to the specified path, allowing overridden parameter types
///
/// Overridden parameter types can be useful, for example some REST-ful APIs do not strictly adhere to spec.
///
/// - Parameters:
/// - path: The path for the DELETE request.
/// - parameterType: The parameters type to be used.
/// - parameters: The parameters to be used, they will be serialized using Percent-encoding and appended to the URL.
/// - completion: The result of the operation, it's an enum with two cases: success and failure.
/// - Returns: The request identifier.
@discardableResult
func delete(_ path: String, parameterType: ParameterType, parameters: Any? = nil, completion: @escaping (_ result: JSONResult) -> Void) -> String {
handleJSONRequest(.delete, path: path, cacheName: nil, parameterType: parameterType, parameters: parameters, responseType: .json, cachingLevel: .none, completion: completion)
}

/// Registers a fake DELETE request for the specified path. After registering this, every DELETE request to the path, will return the registered response.
///
/// - Parameters:
Expand Down
62 changes: 32 additions & 30 deletions Sources/Networking+Private.swift
Original file line number Diff line number Diff line change
Expand Up @@ -347,32 +347,33 @@ extension Networking {
func logError(parameterType: ParameterType?, parameters: Any? = nil, data: Data?, request: URLRequest?, response: URLResponse?, error: NSError?) {
guard isErrorLoggingEnabled else { return }
guard let error = error else { return }
let logger = logProvider.provide(error: error)

print(" ")
print("========== Networking Error ==========")
print(" ")
logger.log(" ")
logger.log("========== Networking Error ==========")
logger.log(" ")

let isCancelled = error.code == NSURLErrorCancelled
if isCancelled {
if let request = request, let url = request.url {
print("Cancelled request: \(url.absoluteString)")
print(" ")
logger.log("Cancelled request: \(url.absoluteString)")
logger.log(" ")
}
} else {
print("*** Request ***")
print(" ")
logger.log("*** Request ***")
logger.log(" ")

print("Error \(error.code): \(error.description)")
print(" ")
logger.log("Error \(error.code): \(error.description)")
logger.log(" ")

if let request = request, let url = request.url {
print("URL: \(url.absoluteString)")
print(" ")
logger.log("URL: \(url.absoluteString)")
logger.log(" ")
}

if let headers = request?.allHTTPHeaderFields {
print("Headers: \(headers)")
print(" ")
logger.log("Headers: \(headers)")
logger.log(" ")
}

if let parameterType = parameterType, let parameters = parameters {
Expand All @@ -382,44 +383,45 @@ extension Networking {
let data = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
let string = String(data: data, encoding: .utf8)
if let string = string {
print("Parameters: \(string)")
print(" ")
logger.log("Parameters: \(string)")
logger.log(" ")
}
} catch let error as NSError {
print("Failed pretty printing parameters: \(parameters), error: \(error)")
print(" ")
logger.log("Failed pretty printing parameters: \(parameters), error: \(error)")
logger.log(" ")
}
case .formURLEncoded:
guard let parametersDictionary = parameters as? [String: Any] else { fatalError("Couldn't cast parameters as dictionary: \(parameters)") }
do {
let formattedParameters = try parametersDictionary.urlEncodedString()
print("Parameters: \(formattedParameters)")
logger.log("Parameters: \(formattedParameters)")
} catch let error as NSError {
print("Failed parsing Parameters: \(parametersDictionary) — \(error)")
logger.log("Failed parsing Parameters: \(parametersDictionary) — \(error)")
}
print(" ")
logger.log(" ")
default: break
}
}

if let data = data, let stringData = String(data: data, encoding: .utf8) {
print("Data: \(stringData)")
print(" ")
logger.log("Data: \(stringData)")
logger.log(" ")
}

if let response = response as? HTTPURLResponse {
print("*** Response ***")
print(" ")
logger.log("*** Response ***")
logger.log(" ")

print("Headers: \(response.allHeaderFields)")
print(" ")
logger.log("Headers: \(response.allHeaderFields)")
logger.log(" ")

print("Status code: \(response.statusCode) — \(HTTPURLResponse.localizedString(forStatusCode: response.statusCode))")
print(" ")
logger.log("Status code: \(response.statusCode) — \(HTTPURLResponse.localizedString(forStatusCode: response.statusCode))")
logger.log(" ")
}
}
print("================= ~ ==================")
print(" ")
logger.log("================= ~ ==================")
logger.log(" ")
logger.flush()
}

func cacheOrPurgeJSON(object: Any?, path: String, cacheName: String?, cachingLevel: CachingLevel) throws {
Expand Down
2 changes: 2 additions & 0 deletions Sources/Networking.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ open class Networking {
URLSession(configuration: self.configuration)
}()

public var logProvider: ErrorLoggerProvider = ConsoleLogProvider()

/// Caching options
public enum CachingLevel {
case memory
Expand Down