Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

swift parse json - The data couldn’t be read because it isn’t in the correct format

Here is struct codable code:

import Foundation

public struct TaskID: Codable {
    let embedded: Embedded
}

public struct Embedded: Codable {
    let task: [Task]
}

public struct Task : Codable {

    let embedded: EmbeddedVariable
    let id : String
    let name: String
    let assignee: String
    let created: String
    let processDefinitionId: String
}

public struct EmbeddedVariable: Codable {

    let variable : [Variables]
}

public struct Variables: Codable {

    let value : String
    let name: String
}

I have tried by codingKey and also tried using _embedded too. Face same issue.

Error log: Response could not be decoded because of error:

 Alamofire.AFError.
 ResponseSerializationFailureReason.decodingFailed(error: Swift.DecodingError.typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil)))))

The data couldn’t be read because it isn’t in the correct format.

Here is the code for JSONSerialization:

      // MARK: - URLRequestConvertible
func asURLRequest() throws -> URLRequest {
    let url = try K.ProductionServer.baseURL.asURL()
    
    var urlRequest = URLRequest(url: url.appendingPathComponent(path))
    print(urlRequest)
    // HTTP Method
    urlRequest.httpMethod = method.rawValue
   
    let authToken = UserDefaults.standard.string(forKey: "authToken")
    let bearerToken: String = "Bearer " + (authToken ?? "")
    print("baearer token::\(bearerToken)")
    
    // Common Headers
    urlRequest.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.acceptType.rawValue)
    urlRequest.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.contentType.rawValue)
    urlRequest.setValue(bearerToken, forHTTPHeaderField: HTTPHeaderField.authentication.rawValue)
    
    // Parameters
    if let parameters = parameters {
        do {
            urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
        } catch {
            throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
        }
    }
    
    return urlRequest
}

Here is the code json return response:

   import Foundation
  import Alamofire

public class APIClient {
@discardableResult
private static func performRequest<T:Decodable>(route:APIRouter, decoder: JSONDecoder = JSONDecoder(), completion:@escaping (AFResult<T>)->Void) -> DataRequest {
            
    return AF.request(route)
                    .responseDecodable (decoder: decoder){ (response: AFDataResponse<T>) in
                        completion(response.result)
                        print("framework response::",response.result)
    }
}

public static func taskID(id: String, completion:@escaping (AFResult<MyTaskData>)->Void) {
    
    performRequest(route: APIRouter.TaskById(id: id), completion: completion)
}


}//APIClient
like image 331
PvUIDev Avatar asked Nov 15 '19 08:11

PvUIDev


2 Answers

In your JSON payload,There is a extra comma at end of the value for key processDefinitionId.

Try this JSON Formatter tool to validate the JSON: jsonformatter

"task":[
        {
         //...

         "id": "412a2aca-06ae-11ea-8860-120ef5ab2c25",
         "name": "Quick Evaluation",
         "assignee": "demo",
         "created": "2019-11-14T07:13:27.558+0000",
         "processDefinitionId": "quickEvaluation:1:129ce2b1-0616-11ea-8860-120ef5ab2c25", // remove this coma(,) from this line

        }

Update:

Use CodingKey for the _embedded. Try the following way

// MARK: - TaskID
struct TaskID: Codable {
    let embedded: Embedded
    let count: Int

    enum CodingKeys: String, CodingKey {
        case embedded = "_embedded"
        case count
    }
}

// MARK: - Embedded
struct Embedded: Codable {
    let task: [Task]
}

// MARK: - Task
struct Task: Codable {
    let embedded: EmbeddedVariable
    let id, name, assignee, created: String
    let processDefinitionID: String

    enum CodingKeys: String, CodingKey {
        case embedded = "_embedded"
        case id, name, assignee, created
        case processDefinitionID = "processDefinitionId"
    }
}

// MARK: - EmbeddedVariable
struct EmbeddedVariable: Codable {
    let variable: [Variable]
}

// MARK: - Variable
struct Variable: Codable {
    let links: Links
    let name, value, type: String
    let valueInfo: ValueInfo

    enum CodingKeys: String, CodingKey {
        case links = "_links"
        case name, value, type, valueInfo
    }
}

// MARK: - Links
struct Links: Codable {
    let linksSelf: SelfClass

    enum CodingKeys: String, CodingKey {
        case linksSelf = "self"
    }
}

// MARK: - SelfClass
struct SelfClass: Codable {
    let href: String
}

// MARK: - ValueInfo
struct ValueInfo: Codable {
}

like image 107
Jakir Hossain Avatar answered Sep 23 '22 14:09

Jakir Hossain


How about changing all embeded to _embeded in codable struct?

In your APIClient class, JSONDecoder instance created with default. and it doesn't change key names during decoding include underscore.

The JSONDecoder.KeyDecodingStrategy.useDefaultKeys strategy is the strategy used if you don't specify one. Documentation from Apple

Code

public struct TaskID: Codable {
    let _embedded: Embedded
}

public struct Task : Codable {

    let _embedded: EmbeddedVariable
    let id : String
    let name: String
    let assignee: String
    let created: String
    let processDefinitionId: String
}
like image 35
Makeeyaf Avatar answered Sep 25 '22 14:09

Makeeyaf