I am trying to query the marvel API. I believe my decodable is wrong. I have the following code:
struct ReturnedData : Decodable {
var id : Int?
var name : String?
var description : String?
}
var savedData : [ReturnedData] = []
let urlString = "https://gateway.marvel.com/v1/public/characters?ts=1&apikey=\(myAPIKey)"
let url = URL(string: urlString)
let session = URLSession.shared
let dataTask = session.dataTask(with: url!) { (data, response, error) in
guard let data = data else {return}
do {
let recievedData = try JSONDecoder().decode([ReturnedData].self, from: data)
self.savedData = recievedData
} catch {
print(error)
}
}
dataTask.resume()
}
I am getting the following error message: typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))
according to the documentation, I should get all of the below: Character
id (int, optional): The unique ID of the character resource., name (string, optional): The name of the character. description (string, optional): A short bio or description of the character. modified (Date, optional): The date the resource was most recently modified. resourceURI (string, optional): The canonical URL identifier for this resource. urls (Array[Url], optional): A set of public web site URLs for the resource. thumbnail (Image, optional): The representative image for this character. comics (ComicList, optional): A resource list containing comics which feature this character. stories (StoryList, optional): A resource list of stories in which this character appears events (EventList, optional): A resource list of events in which this character appears. series (SeriesList, optional): A resource list of series in which this character appears.
Also, any tips on how to get the thumbnail image is appreciated.
CodePudding user response:
The error you get is because the model you have does not match the json data. So, try this approach ...to query the marvel API...
.
In future, copy and paste your json data into https://app.quicktype.io/
this will generate the models for you. Adjust the resulting code to your needs. Alternatively read the docs at: https://developer.marvel.com/docs#!/public/getCreatorCollection_get_0 and create the models by hand from the info given.
class MarvelModel: ObservableObject {
@Published var results = [MarvelResult]()
let myAPIKey = "xxxx"
let myhash = "xxxx"
func getMarvels() async {
guard let url = URL(string: "https://gateway.marvel.com/v1/public/characters?ts=1&apikey=\(myAPIKey)&hash=\(myhash)") else { return }
do {
let (data, _) = try await URLSession.shared.data(from: url)
let response = try JSONDecoder().decode(MarvelResponse.self, from: data)
Task{@MainActor in
results = response.data.results
}
} catch {
print("---> error: \(error)")
}
}
}
struct ContentView: View {
@StateObject var vm = MarvelModel()
var body: some View {
VStack {
if vm.results.isEmpty { ProgressView() }
List(vm.results) { item in
Text(item.name)
}
}
.task {
await vm.getMarvels()
}
}
}
struct MarvelResponse: Decodable {
let code: Int
let status, copyright, attributionText, attributionHTML: String
let etag: String
let data: MarvelData
}
struct MarvelData: Decodable {
let offset, limit, total, count: Int
let results: [MarvelResult]
}
struct MarvelResult: Identifiable, Decodable {
let id: Int
let name, resultDescription: String
let modified: String
let thumbnail: Thumbnail
let resourceURI: String
let comics, series: Comics
let stories: Stories
let events: Comics
let urls: [URLElement]
enum CodingKeys: String, CodingKey {
case id, name
case resultDescription = "description"
case modified, thumbnail, resourceURI, comics, series, stories, events, urls
}
}
struct Comics: Decodable {
let available: Int
let collectionURI: String
let items: [ComicsItem]
let returned: Int
}
struct ComicsItem: Identifiable, Decodable {
let id = UUID()
let resourceURI: String
let name: String
}
struct Stories: Decodable {
let available: Int
let collectionURI: String
let items: [StoriesItem]
let returned: Int
}
struct StoriesItem: Identifiable, Decodable {
let id = UUID()
let resourceURI: String
let name: String
let type: String
}
struct Thumbnail: Decodable {
let path: String
let thumbnailExtension: String
enum CodingKeys: String, CodingKey {
case path
case thumbnailExtension = "extension"
}
}
struct URLElement: Identifiable, Decodable {
let id = UUID()
let type: String
let url: String
}
EDIT-1: if you want something very basic, then try this:
struct ContentView: View {
@State var results = [MarvelResult]()
var body: some View {
List(results) { item in
Text(item.name)
}
.onAppear {
getMarvels()
}
}
func getMarvels() {
let myAPIKey = "xxxx"
let myhash = "xxxx"
guard let url = URL(string: "https://gateway.marvel.com/v1/public/characters?ts=1&apikey=\(myAPIKey)&hash=\(myhash)") else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
if let data = data {
do {
let response = try JSONDecoder().decode(MarvelResponse.self, from: data)
DispatchQueue.main.async {
self.results = response.data.results
}
}
catch {
print(error)
}
}
}.resume()
}
}