Skip to content

Commit

Permalink
Add additional information when decoding the models (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdb1 authored May 24, 2023
1 parent 212ad37 commit 164b45d
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 1 deletion.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,38 @@ A lightweight networking library.
# Usage
* Use HTTPClient.shared for executing your requests.
* You can change the default JsonDecoder if needed.
* If you want to toggle the verbosity of the prints to the console, change the value of the `logResponses` boolean in HTTPClient. It's `true` by default.

## Logging

### Success Decoding Example:

```swift
===> JSON Decoding start:
Model:
CoreNetworkingTests.CatFact
- fact: "The biggest wildcat today is the Siberian Tiger. It can be more than 12 feet (3.6 m) long (about the size of a small car) and weigh up to 700 pounds (317 kg)."
- length: 158
Additional Info:
1 key/value pair
(2 elements)
- key: "UTF8 - String"
- value: "{\"fact\":\"The biggest wildcat today is the Siberian Tiger. It can be more than 12 feet (3.6 m) long (about the size of a small car) and weigh up to 700 pounds (317 kg).\",\"length\":158}"
<=== JSON Decoding end.
```

### Decoding Issue Example:

```swift
===> JSON Decoding issue start:
Error description: Key 'CodingKeys(stringValue: "fact", intValue: nil)' not found
Additional Info:
2 key/value pairs
(2 elements)
- key: "Model"
- value: "CatFact"
(2 elements)
- key: "Context"
- value: "No value associated with key CodingKeys(stringValue: \"fact\", intValue: nil) (\"fact\")."
<=== JSON Decoding issue end.
```
72 changes: 72 additions & 0 deletions Sources/CoreNetworking/DecodingErrorLogger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// DecodingErrorLogger.swift
//
//
// Created by Manu on 24/05/2023.
//

import Foundation

/// Logs error to the console when decoding network models.
struct DecodingErrorLogger {
private let jsonDecoder: JSONDecoder

init(
jsonDecoder: JSONDecoder = JSONDecoder()
) {
self.jsonDecoder = jsonDecoder
}

func logAdditionalDecodingFailureInfo(with error: Error, for type: Decodable.Type) {
var errorDescription: String = ""
var logProperties: [String: String] = [:]
logProperties["Model"] = "\(type)"

if let decodingError = error as? DecodingError {
switch decodingError {
case let .dataCorrupted(context):
// An indication that the data is corrupted or otherwise invalid.
addContext(context, logProperties: &logProperties)
errorDescription = "Corrupted Data"
case let .keyNotFound(key, context):
// An indication that a keyed decoding container was asked for an entry for the given key,
// but did not contain one.
addContext(context, logProperties: &logProperties)
errorDescription = "Key '\(key)' not found"
case let .valueNotFound(value, context):
// An indication that a non-optional value of the given type was expected, but a null value was found.
addContext(context, logProperties: &logProperties)
errorDescription = "Value '\(value)' not found"
case let .typeMismatch(type, context):
// An indication that a value of the given type could not be decoded because
// it did not match the type of what was found in the encoded payload.
addContext(context, logProperties: &logProperties)
errorDescription = "Type '\(type)' mismatch"
default: ()
}
}

print("❌ ===> JSON Decoding issue start:")
print("Error description: \(errorDescription)")
print("Additional Info:")
dump(logProperties)
print("❌ <=== JSON Decoding issue end.")
print("")
}
}

private extension DecodingErrorLogger {
/// Add Decoding Error context information to the dictionary.
func addContext(
_ context: DecodingError.Context,
logProperties: inout [String: String]
) {
logProperties["Context"] = context.debugDescription
if context.codingPath.count > 0 {
logProperties["Coding Path"] = context.codingPath.debugDescription
}
if let underlyingError = context.underlyingError {
logProperties["Underlying Error"] = underlyingError.localizedDescription
}
}
}
24 changes: 24 additions & 0 deletions Sources/CoreNetworking/DecodingSuccessLogger.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// DecodingSuccessLogger.swift
//
//
// Created by Manu on 24/05/2023.
//

import Foundation

/// Logs information to the console when decoding network models.
struct DecodingSuccessLogger {
func logInfo(model: Decodable, data: Data) {
var logProperties: [String: String] = [:]
logProperties["UTF8 - String"] = String(data: data, encoding: .utf8)

print("✅ ===> JSON Decoding start:")
print("Model:")
dump(model)
print("Additional Info:")
dump(logProperties)
print("✅ <=== JSON Decoding end.")
print("")
}
}
16 changes: 15 additions & 1 deletion Sources/CoreNetworking/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ public class HTTPClient {
public static let shared = HTTPClient()
/// Replace the default JSONDecoder if necessary.
public var jsonDecoder: JSONDecoder = JSONDecoder()
/// Determines if the HTTPClient will log information about the responses to the console.
public var logResponses: Bool = true
/// Console logger for successful decodes.
private lazy var decodingSuccessLogger = DecodingSuccessLogger()
/// Console logger for decoding issues.
private lazy var decodingErrorLogger = DecodingErrorLogger(jsonDecoder: jsonDecoder)

/// Executes a request asynchronously and returns a response, or throws an error.
public func execute<Response: Decodable>(
Expand All @@ -27,13 +33,21 @@ public class HTTPClient {
responseType,
from: data
)

if logResponses {
decodingSuccessLogger.logInfo(model: decodedResponse, data: data)
}

return decodedResponse
} catch {
if logResponses {
decodingErrorLogger.logAdditionalDecodingFailureInfo(with: error, for: responseType)
}

guard let decodingError = error as? DecodingError else {
throw Request.RequestError.decode()
}

throw Request.RequestError.decode(decodingError)
}
case 401:
Expand Down

0 comments on commit 164b45d

Please sign in to comment.