Home > Mobile >  decoding key issue swift codable
decoding key issue swift codable

Time:07-11

I have a function which I use to make api call but sometimes, I could get a decaying error and debugging this has been difficult. Below is my function, is there any way to maybe log or print the bad decoding key since I am using combine.

    func request<T>(with builder: BaseRequest, customDecoder: JSONDecoder) -> AnyPublisher<T, APIError> where T: Codable {
        
        let encoding: ParametersEncoder = [.get, .delete].contains(builder.method) ? URLParameretersEncoder() : JSONParametersEncoder()
        customDecoder.keyDecodingStrategy = .convertFromSnakeCase
        var url: URL {
            var components = URLComponents()
            components.scheme = "http"
            components.host = builder.baseUrl
            components.path = "/api/v1"   builder.path
            
            guard let url = components.url else {
                preconditionFailure("Invalid URL components: \(components)")
            }
            
            return url
        }
        var urlRequest = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 46.0)
        urlRequest.httpMethod = builder.method.rawValue
        builder.headers.forEach { key, value in
            urlRequest.setValue(value, forHTTPHeaderField: key)
        }
        if let token = tokenManager.token {
            urlRequest.setValue("Bearer "   token, forHTTPHeaderField: "Authorization")
        }
        if let parameters = builder.parameters {
            guard let encoded = try? encoding.encode(parameters: parameters, in: urlRequest) else {
                fatalError()
            }
            urlRequest = encoded
        }
        self.log(request: urlRequest)
        return URLSession.shared
            .dataTaskPublisher(for: urlRequest)
            .receive(on: DispatchQueue.main)
            .mapError { _ in .unknown }
            .flatMap { data, response -> AnyPublisher<T, APIError> in
                guard let response = response as? HTTPURLResponse else {
                    return Fail(error: APIError.invalidResponse).eraseToAnyPublisher()
                }
                self.log(response: response, data: data, error: nil)
                if (200...299).contains(response.statusCode) {
                    return Just(data)
                        .decode(type: T.self, decoder: customDecoder)
//                        .map {
//                            print($0)
//                            return $0
//                        } //added
                        .mapError {_ in .decodingError}
                        .eraseToAnyPublisher()
                } else {
                    guard let errorResponse = try? customDecoder.decode(BaseResponse.self, from: data) else {
                        return Fail(error: APIError.decodingError).eraseToAnyPublisher()
                    }
                    return Fail(error: APIError.server(response: errorResponse))
                        .eraseToAnyPublisher()
                }
            }
            .eraseToAnyPublisher()
    }

CodePudding user response:

I have been using this snippet to point to the bad decoding key which might help.

if let data = response.data {
    do {
        let decoder = JSONDecoder()
        let messages = try decoder.decode(T.self, from: data)
        print(messages as Any)
    } catch DecodingError.dataCorrupted(let context) {
        print(context)
    } catch DecodingError.keyNotFound(let key, let context) {
        print("Key '\(key)' not found:", context.debugDescription)
        print("codingPath:", context.codingPath)
    } catch DecodingError.valueNotFound(let value, let context) {
        print("Value '\(value)' not found:", context.debugDescription)
        print("codingPath:", context.codingPath)
    } catch DecodingError.typeMismatch(let type, let context) {
        print("Type '\(type)' mismatch:", context.debugDescription)
        print("codingPath:", context.codingPath)
    } catch {
        print("error: ", error)
    }
}

Note that only include it for debugging purposes if decoding an API is not working as expected, and remove it after you have made necessary changes after seeing its output.

  • Related