Giter Club home page Giter Club logo

corenetworking's Introduction

πŸ‘‹ Hola πŸ‘‹

About me πŸ€”

  • I'm Manu, a human from Argentina πŸ‡¦πŸ‡·.
  • I write about software development here.
  • I'm passionate about building software (iOS stuff in particular).
  • I'm a πŸ§‰ (mate) fan.
  • πŸ˜„ Pronouns: He/His.

Hobbies 🎾

I enjoy many different activities in my free time:

  • 🎾 Playing tennis
  • πŸ‹οΈβ€β™€οΈ Going to the gym
  • πŸ“š Reading and being up to date with the industry standards.
  • 🚢🏻 Walking

Ask me about πŸ’¬

I enjoy talking a lot, but these are my favorite topics:

Life Entertainment Food Other
Healthy lifestyle Sports Best burgers in town Software development and processes
Humankind history Cars Best ice cream in town Bitcoin history
Deliberate practice Dad jokes Calories Daily habits and routines
Time management Netflix series Healthy eating habits How to document everything in Notion
Compound interest Sudoku techniques - The correct way of pouring πŸ§‰

corenetworking's People

Stargazers

 avatar  avatar

Watchers

 avatar

corenetworking's Issues

Add more information about the decoding errors

@gentilijuanmanuel I found the piece of code I was looking for:

import Foundation

// sourcery: AutoMockable
// Represents object that is able to log decoding errors in details
protocol DecodingErrorLogging: AnyObject {
    /// This method is used to debug decoding failures
    /// - Parameters:
    ///   - error: Error to log information on
    ///   - type: Type that decoding was attempted for
    func logAdditionalDecodingFailureInfo(with error: Error, for type: Decodable.Type)
}

/// Class that logs error on decoding network models
final class DecodingErrorLogger: DecodingErrorLogging {
    private let jsonDecoder: JSONDecoding
    private let loggerService: Logging

    init(
        jsonDecoder: JSONDecoding = BFJSONDecoder(keyDecodingStrategy: .convertFromSnakeCase),
        loggerService: Logging = NetworkingServiceLocator.logger
    ) {
        self.jsonDecoder = jsonDecoder
        self.loggerService = loggerService
    }

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

        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 = LoggerPropertyKeys.dataCorrupted.rawValue
            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: ()
            }
        }
        logProperties[.decodingError] = errorDescription ?? error.localizedDescription
        logProperties[.model] = "\(type)"

        // Log as warning so the information reaches AppCenter Crash reports
        loggerService.log(.warn, .decodingFailure, properties: logProperties)
    }
}

private extension DecodingErrorLogger {
    /// Add Decoding Error context information to the dictionary
    func addContext(
        _ context: DecodingError.Context,
        logProperties: inout [LoggerPropertyKeys: String]
    ) {
        logProperties[.contextProperty] = context.debugDescription
        logProperties[.codingPathProperty] = context.codingPath.debugDescription
        logProperties[.underlyingErrorProperty] = context.underlyingError.debugDescription
    }
}

Is something like that, basically, it prints more information about the particular error in the decoding phase.

Maybe we can add something similar to this to this package πŸ˜„

Add more granularity to the verbosity configuration object

Ideally, we want to provide more granularity to the verbose level of the library.

Example:
Instead of:

    public enum Configuration {
        /// Verbose: logs requests/responses to the console based on the associated values.
        case verbose(logRequests: Bool, logResponses: Bool)
        /// Quiet: doesn't log anything.
        case quiet
    }

Use:

    /// Configuration options.
    public enum Configuration {
        /// Verbose: logs requests/responses to the console based on the associated values.
        case verbose(
            requestConfiguration: RequestConfiguration,
            responseConfiguration: ResponseConfiguration
        )
        /// Quiet: doesn't log anything.
        case quiet

        public struct RequestConfiguration {
            var logInternalId: Bool
            var logURL: Bool
            var logHTTPMethod: Bool
            var logHTTPHeaders: Bool
            var logHTTPBody: Bool
        }

        public struct ResponseConfiguration {
            var logInternalId: Bool
            var logURL: Bool
            var logStatusCode: Bool
            var logJSONResponse: Bool
            var logExpectedModel: Bool
            var logDecodingResult: Bool
        }
    }

Add NullCodable capabilities

Some requests require the json objects to explicitly use "null", add the NullCodable struct to handle those scenarios

//
//  JSONEncoder+NullCodable.swift
//
//
//  Created by Manu on 17/05/2023.
//  Based on: https://github.com/g-mark/NullCodable

import Foundation

/// Property wrapper that encodes `nil` optional values as `null`
/// when encoded using `JSONEncoder`.
///
/// For example, adding `@NullCodable` like this:
/// ```swift
/// struct Test: Codable {
///     @NullCodable var name: String? = nil
/// }
/// ```
/// will encode as: "{\\"name\\": null}" - as opposed to the default,
/// which is to omit the property from the encoded json, like: "{}".
@propertyWrapper
public struct NullCodable<Wrapped> {
    /// The wrapper value.
    public var wrappedValue: Wrapped?

    /// Initializer.
    public init(wrappedValue: Wrapped?) {
        self.wrappedValue = wrappedValue
    }
}

extension NullCodable: Encodable where Wrapped: Encodable {
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch wrappedValue {
        case let .some(value):
            try container.encode(value)
        case .none:
            try container.encodeNil()
        }
    }
}

extension NullCodable: Decodable where Wrapped: Decodable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if !container.decodeNil() {
            wrappedValue = try container.decode(Wrapped.self)
        }
    }
}

extension NullCodable: Equatable where Wrapped: Equatable {}

public extension KeyedDecodingContainer {
    /// Decoding method.
    func decode<Wrapped>(
        _: NullCodable<Wrapped>.Type,
        forKey key: KeyedDecodingContainer<K>.Key
    ) throws -> NullCodable<Wrapped> where Wrapped: Decodable {
        try decodeIfPresent(NullCodable<Wrapped>.self, forKey: key) ?? NullCodable<Wrapped>(wrappedValue: nil)
    }
}

Add ability to mock responses

Add ability to use mocked responses in the library instead of actually hitting the network.

This will be useful for quickly testing behaviors (success/error responses) and for the unit tests to avoid hitting the network.

Ideally, we might want to have:

  • Ability to set global approach (mock vs real)
  • Ability to add delay for the mocks (to be able to visually check the loading states)
  • Ability to use a mock response for a specific request (vs global approach)
  • Ability to load mock responses from json files
  • Ability to load mock responses from in-lined json strings

I think @juansanzone has some great ideas on how to accomplish this. Feel free to raise any input/concerns you may have πŸ˜„

Add Encoding capabilities

  • Add the extension to Encodable to transform an object to a dictionary.
public extension Encodable {
    /// Creates a json dictionary from an Encodable Object
    var toJsonDictionary: [String: Any] {
        let jsonEncoder: JSONEncoder = .default
        guard let data = try? jsonEncoder.encode(self) else { return [:] }
        let dictionary = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
        return dictionary ?? [:]
    }
}
  • Add the JSONEncoder to the HTTPClient and a convenient way to use Encodable models for post/put requests' bodies

Add Networking Time logging

Add the ability to log how much time was spent on a particular request.

Also add this option to the configuration object from #4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.