I am really new to swift. I am trying an API call, but it just returns an empty array. I am really not sure where I am going wrong. I have been following a couple of tutorials, but it just returns an empty array.
I am not sure if I have defined the model properly or maybe it's going wrong where I am trying to fetch data from the API. I have tried used POSTMAN, to make sure the API is working and it's pulling back results I am trying to pull data from this API here https://docs.trefle.io/docs/advanced/plants-fields#tag/Corrections/operation/createCorrection . I have attached my below code here
import UIKit
import SwiftUI
struct PlantResponse: Codable {
let data : [Plant]
}
struct Plant: Codable {
let id: Int
let common_name: String
let slug: String
let scientific_name: String
let year: Int
let bibliography: String
let author: String
let status: String
let rank: String
let family_common_name: String
let family: String
let genus_id: Int
let genus: String
let image_url: String
var synonyms = [String]()
var links = [String]()
}
func fetchPlantsFromAPI() async throws -> [Plant] {
let url = URL(string: "https://trefle.io/api/v1/plants?token=.[MYTOKEN]&filter[common_name]=beach%20strawberry")!
let (data, _) = try await URLSession.shared.data(from: url)
do {
let decoded = try JSONDecoder().decode(PlantResponse.self, from: data)
return decoded.data
} catch {
print(error)
return [Plant]()
}
}
Task {
try await fetchPlantsFromAPI()
}
Below is the output I get when I run it on playground
Below is the output I get when I run on POSTMAN
{ "data": [ { "id": 263319, "common_name": "Beach strawberry", "slug": "fragaria-chiloensis", "scientific_name": "Fragaria chiloensis", "year": 1768, "bibliography": "Gard. Dict. ed. 8 : n.° 4 (1768)", "author": "(L.) Mill.", "status": "accepted", "rank": "species", "family_common_name": "Rose family", "genus_id": 12147, "image_url": "https://bs.plantnet.org/image/o/8ee87e6f94833055db1c7df5fc07761852b7b1eb", "synonyms": [ "Fragaria vesca var. chiloensis", "Potentilla chiloensis" ], "genus": "Fragaria", "family": "Rosaceae", "links": { "self": "/api/v1/species/fragaria-chiloensis", "plant": "/api/v1/plants/fragaria-chiloensis", "genus": "/api/v1/genus/fragaria" } } ], "links": { "self": "/api/v1/plants?filter%5Bcommon_name%5D=beach+strawberry", "first": "/api/v1/plants?filter%5Bcommon_name%5D=beach+strawberry&page=1", "last": "/api/v1/plants?filter%5Bcommon_name%5D=beach+strawberry&page=1" }, "meta": { "total": 1 } }
Thanks for your help.

The
Plantdefinition does not match the JSON payload. As a result,JSONDecoderis undoubtedly throwing an error (which was undoubtedly printed to the console). You must look at the console to see what the error was.As an aside, I would advise against
return [Plant]()(returning an empty array). Instead, I would print the error and then rethrow it withthrow error. That way, the caller can catch any errors, and reflect that in the UI accordingly. This is probably why it “returns an empty array”, not because the network response was empty, but rather that there was a decoding error andfetchPlantsFromAPIcaught the error, printed it, but then immediately returned an empty array.FWIW, when I decoded your JSON, I received the following error:
That error is telling you that
linksis a dictionary in the JSON, but not defined as such in your object. Instead one might want to definelinksinPlantto be a dictionary,[String: String]or[String: URL]. Or, better, given that the keys used in this dictionary are fixed, it would be better to use custom subtype:Note, in addition to redefining
links, I also used the standard camelcase property names inPlant, and instructed theJSONDecoderto convert the JSON snakecase keys to camelcase property names.But do not get lost in these details: The key observation is that you should look at the
Errorthat was thrown to diagnose what went wrong.Just so we can more clearly read the JSON, here it is in “pretty” format:
FWIW, I use https://jsonlint.com to check the JSON and render it in a pretty format.
Again, the
linksin this JSON is a dictionary which can be decoded as its own type.