Search code examples
iosswiftnshttpurlresponse

Problem parsing JSON data from server Swift


I'm trying to parse data from the server, but I get this error:

failure(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 parameters should be passed as an array of objects, as well as the response object. I can't figure out what should I change in my code so the response is well structured. This is what a response looks like:

[
  {
   'code' : number, 
   'error' => boolean, 
   'code_error' => number, 
   'data_error' => string, 
   'message' => 'Falta Campo requerido'
  }
]

These are the parameters that should be passed:

[
   {
      'email' => 'required|string|email',
      'event_type' => 'required|string',
      'watermark' => 'required|string',
      'date' => 'required',
      'location' => 'required|string',
      'segment' => 'required',
      'time' => 'required',
      'country' => 'required',
      'city' => 'required'
    }
]

And this is what my code looks like.

Data:

struct MarcaAguaResData: Codable {
    let code: Int
    let error: Bool
    let message: String
}

struct MarcaAguaErrorResponse: Decodable, LocalizedError {
    let code: Int
    let error: Bool
    let message: String
    let code_error: Int
    let data_error: String
}

Server:

class MarcaAguaService {
    func marcaAgua(parameters: [String: Any],
                completion: @escaping (Result<MarcaAguaResData, Error>)-> Void) {
    
    let urlString =  baseUrl + "events"
    
    guard let url = URL(string: urlString) else {
        completion(.failure(NetworkingError.badUrl))
        return
    }
    
    var request = URLRequest(url: url)
    var components = URLComponents()
    var queryItems = [URLQueryItem]()
    
    for (key, value) in parameters {
        let queryItem = URLQueryItem(name: key, value: String(describing: value))
        queryItems.append(queryItem)
    }
    
    
    components.queryItems = queryItems
    
    let queryItemsData = components.query?.data(using: .utf8)
    
    request.httpBody = queryItemsData
    request.httpMethod = "POST"
    request.setValue("Bearer \(token_login)", forHTTPHeaderField: "Authorization")
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    
    let session = URLSession.shared
    
    let task = session.dataTask(with: request) { (data, response, error) in
        DispatchQueue.main.async {
            guard let unwrappedResponse = response as? HTTPURLResponse else {
                completion(.failure(NetworkingError.badResponse))
                return
            }
            
            switch unwrappedResponse.statusCode {
            case 200 ..< 300:
                print("success")
            default:
                print("failure")
            }
            
            if let unwrappedError = error {
                completion(.failure(unwrappedError))
                return
            }
            
            if let unwrappedData = data {
                do{
                    let json = try JSONSerialization.jsonObject(with: unwrappedData, options: .allowFragments)
                    print("BBBB")
                    print(json)
                    
                    if let successRes = try? JSONDecoder().decode(MarcaAguaResData.self, from: unwrappedData){
                        completion(.success(successRes))
                    }else{
                      
                        let errorResponse = try JSONDecoder().decode(MarcaAguaErrorResponse.self, from: unwrappedData)
                        print("Error \(errorResponse)")
                        completion(.failure(errorResponse))
                    }
                }catch{
                    print("AAA")
                    completion(.failure(error))
                }
            }
        }
    }
    task.resume()
}
}

Solution

  • To be [MarcaAguaResData].self which is an array instead of MarcaAguaResData.self which is a dictionary

     if let successRes = try? JSONDecoder().decode([MarcaAguaResData].self, from: unwrappedData){
       completion(.success(successRes))
     }else{
        let errorResponse = try JSONDecoder().decode([MarcaAguaErrorResponse].self, from: unwrappedData)
        print("Error \(errorResponse)")
        completion(.failure(errorResponse))
     }
    

    With

    completion: @escaping (Result<[MarcaAguaResData], Error>)-> Void)