I'm currently having trouble with utilizing the PokeApi. I have code that allows me to view a pokemon's name and URL to the other JSON for a pokemon, but I'm not quite sure how I would retrieve that data. Here is what I have so far. And here is the link to the api! let pokeList = https://pokeapi.co/api/v2/pokemon?limit=100000&offset=0
import Foundation
// MARK: - Pokemon
struct PokemonList: Codable {
let count: Int
let results: [Result]
}
// MARK: - Result
struct Result: Codable, Identifiable {
let id = UUID()
let name: String
let url: String
enum CodingKeys: String, CodingKey {
case name, url
}
}
// MARK: - Pokemon
struct Pokemon: Codable, Identifiable {
let abilities: [Ability]
let baseExperience: Int
let forms: [Species]
let gameIndices: [GameIndex]
let height: Int
let id: Int
let isDefault: Bool
let locationAreaEncounters: String
let moves: [Move]
let name: String
let order: Int
let species: Species
let sprites: Sprites
let stats: [Stat]
let types: [TypeElement]
let weight: Int
}
// MARK: - Ability
struct Ability: Codable {
let ability: Species
let isHidden: Bool
let slot: Int
}
// MARK: - Species
struct Species: Codable {
let name: String
let url: String
}
// MARK: - GameIndex
struct GameIndex: Codable{
let gameIndex: Int
let version: Species
}
// MARK: - Move
struct Move: Codable {
let move: Species
}
// MARK: - Sprites
struct Sprites: Codable {
let backDefault: String
let backFemale: String
let backShiny: String
let backShinyFemale: String
let frontDefault: String
let frontFemale: String
let frontShiny: String
let frontShinyFemale: String
}
// MARK: - Home
struct Home: Codable {
let frontDefault: String
let frontFemale: String
let frontShiny: String
let frontShinyFemale: String
}
// MARK: - Other
struct Other: Codable {
let home: Home
let officialArtwork: OfficialArtwork
}
// MARK: - OfficialArtwork
struct OfficialArtwork: Codable {
let frontDefault: String
}
// MARK: - Stat
struct Stat: Codable {
let baseStat: Int
let effort: Int
let stat: Species
}
// MARK: - TypeElement
struct TypeElement: Codable {
let slot: Int
let type: Species
}
Code for Webservice to retrieve API Call import Foundation
class PokeWebService: ObservableObject{
@Published var pokeList: PokemonList?
@Published var pokemonIndvl: Pokemon?
func getPokemonList() async throws {
let (data, _) = try await URLSession.shared.data(from: Constants.url.pokeList)
Task{@MainActor in
self.pokeList = try JSONDecoder().decode(PokemonList.self, from: data)
}
}
func getPokemonFromPokemonList(invlURL: String) async throws{
var plURL: URL = URL(string: invlURL)!
let (data, _) = try await URLSession.shared.data(from: plURL)
Task{@MainActor in
self.pokemonIndvl = try JSONDecoder().decode(Pokemon.self, from: data)
}
}
}
My Content View
import SwiftUI
struct PokeListView: View {
@EnvironmentObject var pokeWebService: PokeWebService
var body: some View {
List(pokeWebService.pokeList?.results ?? []){ pokemon in // <-- here
Text(pokemon.name)
Text(pokemon.url)
}
.task {
do{
try await pokeWebService.getPokemonList()
} catch{
print("---> task error: \(error)")
}
}
}
}
struct PokeListView_Previews: PreviewProvider {
static var previews: some View {
PokeListView()
.environmentObject(PokeWebService())
}
}
Since I'm still fairly new to working with APIs in Swift, how would I retrieve the data from the Pokemon.url?
Thank you!
try something like this approach (note the different model structs). You will need to find from the server docs, which fields are optional and adjust the various structs:
import Foundation
import SwiftUI
struct ContentView: View {
@StateObject var pokeWebService = PokeWebService()
var body: some View {
PokeListView().environmentObject(pokeWebService)
}
}
struct PokeListView: View {
@EnvironmentObject var pokeWebService: PokeWebService
var body: some View {
NavigationStack {
List(pokeWebService.pokeList?.results ?? []){ pokemon in
NavigationLink(pokemon.name, value: pokemon.url)
}
.navigationDestination(for: String.self) { urlString in
PokeDetailsView(urlString: urlString)
}
}
.environmentObject(pokeWebService)
.task {
do {
try await pokeWebService.getPokemonList()
} catch{
print("---> PokeListView error: \(error)")
}
}
}
}
struct PokeDetailsView: View {
@EnvironmentObject var pokeWebService: PokeWebService
@State var urlString: String
var body: some View {
VStack {
Text(pokeWebService.pokemonIndvl?.name ?? "no name")
Text("height: \(pokeWebService.pokemonIndvl?.height ?? 0)")
// ... other info
}
.task {
do {
try await pokeWebService.getPokemon(from: urlString)
} catch{
print("---> PokeDetailsView error: \(error)")
}
}
}
}
class PokeWebService: ObservableObject{
@Published var pokeList: PokemonList?
@Published var pokemonIndvl: Pokemon?
func getPokemonList() async throws {
let (data, _) = try await URLSession.shared.data(from: Constants.url.pokeList)
Task{@MainActor in
self.pokeList = try JSONDecoder().decode(PokemonList.self, from: data)
}
}
func getPokemon(from urlString: String) async throws {
if let url = URL(string: urlString) {
let (data, _) = try await URLSession.shared.data(from: url)
Task{@MainActor in
self.pokemonIndvl = try JSONDecoder().decode(Pokemon.self, from: data)
}
}
}
}
// using https://app.quicktype.io/
// MARK: - PokemonList
struct PokemonList: Codable {
let count: Int
let results: [ListItem] // <-- don't use the word Result
}
// MARK: - ListItem
struct ListItem: Codable, Identifiable {
let id = UUID()
let name: String
let url: String
enum CodingKeys: String, CodingKey {
case name, url
}
}
struct HeldItem: Codable {
let item: Species
let versionDetails: [VersionDetail]
enum CodingKeys: String, CodingKey {
case item
case versionDetails = "version_details"
}
}
struct VersionDetail: Codable {
let rarity: Int
let version: Species
}
// MARK: - Pokemon
struct Pokemon: Codable, Identifiable {
let abilities: [Ability]
let baseExperience: Int
let forms: [Species]
let gameIndices: [GameIndex]
let height: Int
let heldItems: [HeldItem]
let id: Int
let isDefault: Bool
let locationAreaEncounters: String
let moves: [Move]
let name: String
let order: Int
let pastTypes: [String]
let species: Species
let sprites: Sprites
let stats: [Stat]
let types: [TypeElement]
let weight: Int
enum CodingKeys: String, CodingKey {
case abilities
case baseExperience = "base_experience"
case forms
case gameIndices = "game_indices"
case height
case heldItems = "held_items"
case id
case isDefault = "is_default"
case locationAreaEncounters = "location_area_encounters"
case moves, name, order
case pastTypes = "past_types"
case species, sprites, stats, types, weight
}
}
// MARK: - Ability
struct Ability: Codable {
let ability: Species
let isHidden: Bool
let slot: Int
enum CodingKeys: String, CodingKey {
case ability
case isHidden = "is_hidden"
case slot
}
}
// MARK: - Species
struct Species: Codable {
let name: String
let url: String
}
// MARK: - GameIndex
struct GameIndex: Codable {
let gameIndex: Int
let version: Species
enum CodingKeys: String, CodingKey {
case gameIndex = "game_index"
case version
}
}
// MARK: - Move
struct Move: Codable {
let move: Species
let versionGroupDetails: [VersionGroupDetail]
enum CodingKeys: String, CodingKey {
case move
case versionGroupDetails = "version_group_details"
}
}
// MARK: - VersionGroupDetail
struct VersionGroupDetail: Codable {
let levelLearnedAt: Int
let moveLearnMethod, versionGroup: Species
enum CodingKeys: String, CodingKey {
case levelLearnedAt = "level_learned_at"
case moveLearnMethod = "move_learn_method"
case versionGroup = "version_group"
}
}
// MARK: - GenerationV
struct GenerationV: Codable {
let blackWhite: Sprites
enum CodingKeys: String, CodingKey {
case blackWhite = "black-white"
}
}
// MARK: - GenerationIv
struct GenerationIv: Codable {
let diamondPearl, heartgoldSoulsilver, platinum: Sprites
enum CodingKeys: String, CodingKey {
case diamondPearl = "diamond-pearl"
case heartgoldSoulsilver = "heartgold-soulsilver"
case platinum
}
}
// MARK: - Versions
struct Versions: Codable {
let generationI: GenerationI
let generationIi: GenerationIi
let generationIii: GenerationIii
let generationIv: GenerationIv
let generationV: GenerationV
let generationVi: [String: Home]
let generationVii: GenerationVii
let generationViii: GenerationViii
enum CodingKeys: String, CodingKey {
case generationI = "generation-i"
case generationIi = "generation-ii"
case generationIii = "generation-iii"
case generationIv = "generation-iv"
case generationV = "generation-v"
case generationVi = "generation-vi"
case generationVii = "generation-vii"
case generationViii = "generation-viii"
}
}
// MARK: - Sprites
class Sprites: Codable {
let backDefault: String
let backFemale: String?
let backShiny: String
let backShinyFemale: String?
let frontDefault: String
let frontFemale: String?
let frontShiny: String
let frontShinyFemale: String?
let other: Other?
let versions: Versions?
let animated: Sprites?
enum CodingKeys: String, CodingKey {
case backDefault = "back_default"
case backFemale = "back_female"
case backShiny = "back_shiny"
case backShinyFemale = "back_shiny_female"
case frontDefault = "front_default"
case frontFemale = "front_female"
case frontShiny = "front_shiny"
case frontShinyFemale = "front_shiny_female"
case other, versions, animated
}
}
// MARK: - GenerationI
struct GenerationI: Codable {
let redBlue, yellow: RedBlue
enum CodingKeys: String, CodingKey {
case redBlue = "red-blue"
case yellow
}
}
// MARK: - RedBlue
struct RedBlue: Codable {
let backDefault, backGray, backTransparent, frontDefault: String
let frontGray, frontTransparent: String
enum CodingKeys: String, CodingKey {
case backDefault = "back_default"
case backGray = "back_gray"
case backTransparent = "back_transparent"
case frontDefault = "front_default"
case frontGray = "front_gray"
case frontTransparent = "front_transparent"
}
}
// MARK: - GenerationIi
struct GenerationIi: Codable {
let crystal: Crystal
let gold, silver: Gold
}
// MARK: - Crystal
struct Crystal: Codable {
let backDefault, backShiny, backShinyTransparent, backTransparent: String
let frontDefault, frontShiny, frontShinyTransparent, frontTransparent: String
enum CodingKeys: String, CodingKey {
case backDefault = "back_default"
case backShiny = "back_shiny"
case backShinyTransparent = "back_shiny_transparent"
case backTransparent = "back_transparent"
case frontDefault = "front_default"
case frontShiny = "front_shiny"
case frontShinyTransparent = "front_shiny_transparent"
case frontTransparent = "front_transparent"
}
}
// MARK: - Gold
struct Gold: Codable {
let backDefault, backShiny, frontDefault, frontShiny: String
let frontTransparent: String?
enum CodingKeys: String, CodingKey {
case backDefault = "back_default"
case backShiny = "back_shiny"
case frontDefault = "front_default"
case frontShiny = "front_shiny"
case frontTransparent = "front_transparent"
}
}
// MARK: - GenerationIii
struct GenerationIii: Codable {
let emerald: Emerald
let fireredLeafgreen, rubySapphire: Gold
enum CodingKeys: String, CodingKey {
case emerald
case fireredLeafgreen = "firered-leafgreen"
case rubySapphire = "ruby-sapphire"
}
}
// MARK: - Emerald
struct Emerald: Codable {
let frontDefault, frontShiny: String
enum CodingKeys: String, CodingKey {
case frontDefault = "front_default"
case frontShiny = "front_shiny"
}
}
// MARK: - Home
struct Home: Codable {
let frontDefault: String
let frontFemale: String?
let frontShiny: String
let frontShinyFemale: String?
enum CodingKeys: String, CodingKey {
case frontDefault = "front_default"
case frontFemale = "front_female"
case frontShiny = "front_shiny"
case frontShinyFemale = "front_shiny_female"
}
}
// MARK: - GenerationVii
struct GenerationVii: Codable {
let icons: DreamWorld
let ultraSunUltraMoon: Home
enum CodingKeys: String, CodingKey {
case icons
case ultraSunUltraMoon = "ultra-sun-ultra-moon"
}
}
// MARK: - DreamWorld
struct DreamWorld: Codable {
let frontDefault: String
let frontFemale: String?
enum CodingKeys: String, CodingKey {
case frontDefault = "front_default"
case frontFemale = "front_female"
}
}
// MARK: - GenerationViii
struct GenerationViii: Codable {
let icons: DreamWorld
}
// MARK: - Other
struct Other: Codable {
let dreamWorld: DreamWorld
let home: Home
let officialArtwork: OfficialArtwork
enum CodingKeys: String, CodingKey {
case dreamWorld = "dream_world"
case home
case officialArtwork = "official-artwork"
}
}
// MARK: - OfficialArtwork
struct OfficialArtwork: Codable {
let frontDefault: String
enum CodingKeys: String, CodingKey {
case frontDefault = "front_default"
}
}
// MARK: - Stat
struct Stat: Codable {
let baseStat, effort: Int
let stat: Species
enum CodingKeys: String, CodingKey {
case baseStat = "base_stat"
case effort, stat
}
}
// MARK: - TypeElement
struct TypeElement: Codable {
let slot: Int
let type: Species
}
EDIT-1:
if you have problems with the NavigationStack
, use this NavigationView
instead.
NavigationView {
List(pokeWebService.pokeList?.results ?? []){ pokemon in
NavigationLink(destination: PokeDetailsView(urlString: pokemon.url)) {
Text(pokemon.name)
}
}
}