Analizando Json desde una Web API
Hola, mi nombre es Nico,
Soy un principiante en programación de aplicaciones/SwiftUI.
Estoy intentando analizar datos json de una API web pero por alguna razón no puedo analizar los datos correctamente. Supongo que mi estructura json no es correcta, pero no puedo encontrar el problema.
El Json que obtengo de la API web se ve algo así:
{
“pois”: [
{
“id”: “2635094451”,
“lat”: “52.410150”,
“lat_s”: “52.4”,
“lng”: “10.776630”,
“lng_s”: “10.8”,
“street”: “Röntgenstraße”,
“content”: “8137285512”,
“backend”: “0-239283152”,
“type”: “1”,
“vmax”: “50”,
“counter”: “0”,
“create_date”: “2021-11-18 13:21:50”,
“confirm_date”: “2021-11-18 13:21:43”,
“gps_status”: “-“,
“info”: ” {\”qltyCountryRoad\”:1,\”confirmed\”:\”0\”,\”gesperrt\”:\”0\”,\”precheck\”:\”[Q1|21|0]\”}”,
“polyline”: “”
}
],
“grid”: []
}
Mi estructura se ve así:
struct APIResponse: Codable {
let pois: [InputDataPois]
let grid: [InputDataGrid]
private enum CodingKeys: String, CodingKey {
case pois
case grid
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.pois = try container.decode(APIResponse.self, forKey: .pois).pois
self.grid = try container.decode(APIResponse.self, forKey: .grid).grid
}
}
struct InputDataPois: Codable, Identifiable {
let id:String
let lat:String
let lat_s:String
let lng:String
let lng_s:String
let street:String
let content:String
let backend:String
let type:String
let vmax:String
let counter:String
let create_date:String
let confirm_date:String
let gps_status:String
let info:String
let polyline:String
}
extension InputDataPois {
private enum CodingKeys: String, CodingKey {
case id
case lat
case lat_s
case lng
case lng_s
case street
case content
case backend
case type
case vmax
case counter
case create_date
case confirm_date
case gps_status
case info
case polyline
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(String.self, forKey: .id)
self.lat = try container.decode(String.self, forKey: .lat)
self.lat_s = try container.decode(String.self, forKey: .lat_s)
self.lng = try container.decode(String.self, forKey: .lng)
self.lng_s = try container.decode(String.self, forKey: .lng_s)
self.street = try container.decode(String.self, forKey: .street)
self.content = try container.decode(String.self, forKey: .content)
self.backend = try container.decode(String.self, forKey: .backend)
self.type = try container.decode(String.self, forKey: .type)
self.vmax = try container.decode(String.self, forKey: .vmax)
self.counter = try container.decode(String.self, forKey: .counter)
self.create_date = try container.decode(String.self, forKey: .create_date)
self.confirm_date = try container.decode(String.self, forKey: .confirm_date)
self.gps_status = try container.decode(String.self, forKey: .gps_status)
self.info = try container.decode(String.self, forKey: .info)
self.polyline = try container.decode(String.self, forKey: .polyline)
}
}
struct InputDataGrid: Codable {
}
Y mi paquete se ve así:
extension Bundle {
func decode(_ file: String) -> [InputDataPois] {
// 1. Localiza el archivo Json
guard let url = URL(string: file) else {
fatalError(“Error al localizar (file) en el paquete”)
}
// 2. Crea una propiedad para los datos
guard let data = try? Data(contentsOf: url) else {
fatalError("Error al cargar \(file) desde el paquete.")
}
// 3. Crea una propiedad para los datos
let str = String(decoding: data, as: UTF8.self)
print("\(str)")
guard let loaded = try? JSONDecoder().decode(APIResponse.self, from: data).pois else {
fatalError("Error al decodificar \(file) del paquete.")
}
// 4. Retorna los datos listos para usar
return loaded
}
}
Y en mi vista estoy usando:
let speed: [InputDataPois] = Bundle.main.decode(“https://cdn2.atudo.net/api/1.0/vl.php?type=0,1,2,3,4,5,6&box=52.36176390234046,10.588760375976562,52.466468685912744,11.159706115722656”)
El error que estoy obteniendo se parece a esto:
(ErrorMessage)[https://i.stack.imgur.com/HoaoC.png]
(ConsoleError)[https://i.stack.imgur.com/aA2tW.png]
Gracias de antemano por su ayuda.
davy.ai
Solución:
Al analizar los mensajes de error, parece que el problema se encuentra en la decodificación de los datos JSON. En concreto, el mensaje de error “Se esperaba un Array pero se encontró un diccionario.” sugiere que los datos JSON pueden no estar estructurados como se esperaba.
Según el ejemplo de datos JSON proporcionado, parece que el campo “pois” es una matriz de objetos, mientras que el campo “grid” es una matriz vacía. Sin embargo, en la estructura
APIResponse
, ambos campos están definidos como matrices de diferentes tipos de datos. Parece que hay una discrepancia entre los datos y la estructura de datos definida.Para solucionar este problema, podrías intentar actualizar la estructura
APIResponse
para que coincida con la estructura de los datos JSON. Aquí hay una versión actualizada de la estructuraAPIResponse
:En esta versión actualizada, el campo
pois
se decodifica directamente como un array deInputDataPois
, mientras que el campogrid
se define como un array deAny
. Esto debería permitir que los datos JSON se analicen correctamente, sin encontrar errores de decodificación.Una vez que se actualiza la estructura
APIResponse
, deberías poder utilizarla como antes para decodificar los datos JSON en la extensiónBundle
. Aquí está la versión actualizada de la extensiónBundle
:En esta versión actualizada, la cadena de URL se convierte en un objeto URL antes de cargar los datos. Se crea el decodificador JSON con la estructura
APIResponse
actualizada y se extrae y devuelve el arraypois
decodificado.Con estas actualizaciones, deberías poder decodificar correctamente los datos JSON y utilizarlos en tu aplicación. Hazme saber si tienes alguna pregunta o problema adicional.