In the realm of app development, mastering the integration of APIs is crucial. The ability to fetch and handle data from external sources is a fundamental skill. Let’s dive into a simple yet insightful Swift app that interacts with the PokeAPI, fetching Pokémon data and learning key concepts along the way.
Model – Pokémon
The Pokemon
struct is a fundamental part of our app’s data structure. It conforms to the Codable
protocol, allowing for easy encoding and decoding of JSON data.
import Foundation
struct Pokemon: Codable {
let id: Int
let name: String
}
This struct defines the basic blueprint for a Pokémon object, containing two essential properties: id
for the Pokémon’s identification number and name
for its name.
PokeAPIManager
The PokeAPIManager
class encapsulates the logic to interact with the PokeAPI and fetch Pokémon data based on the provided ID. It employs error handling using an enum
called APIError
to manage potential issues during the API request.
import Foundation
import SwiftUI
enum APIError: Error {
case invalidURL
case requestFailed
}
final class PokeAPIManager {
func fetchPokemon(withID id: Int, completion: @escaping(Result<Pokemon, APIError>) -> Void) {
guard let url = URL(string: "https://pokeapi.co/api/v2/pokemon/\(id)") else {
completion(.failure(.invalidURL))
return
}
let task = URLSession.shared.dataTask(with: url) { data, _, error in
if let error = error {
completion(.failure(.requestFailed))
print("Error: \(error.localizedDescription)")
return
}
guard let data = data else {
completion(.failure(.requestFailed))
return
}
do {
let pokemon = try JSONDecoder().decode(Pokemon.self, from: data)
completion(.success(pokemon))
} catch {
completion(.failure(.requestFailed))
print("Error decoding data: \(error.localizedDescription)")
}
}
task.resume()
}
}
The fetchPokemon
method takes an id
parameter and a completion handler as its arguments. Inside this method, it constructs a URL based on the given ID, creates a data task using URLSession
, and then manages potential errors and decodes the retrieved data. Upon successful retrieval, it calls the completion handler with a .success
case containing the fetched Pokémon or a .failure
case with the corresponding error from the APIError
enum.
PokemonView – SwiftUI Interface
The PokemonView
struct is a SwiftUI view that serves as the user interface for our app. It displays the Pokémon information fetched from the API and includes functionality to trigger the data retrieval process.
import SwiftUI
struct HomeView: View {
@State private var pokemon: Pokemon?
private let apiManager = PokeAPIManager()
var body: some View {
VStack(spacing: 28) {
if let pokemon = pokemon {
Text("ID: \(pokemon.id)")
Text("Pokemon Name: \(pokemon.name)")
} else {
ProgressView()
}
Button("FetchPokemon") {
fetchPokemon()
}
}
.onAppear {
fetchPokemon()
}
}
private func fetchPokemon() {
let randomID = Int.random(in: 1...100)
apiManager.fetchPokemon(withID: randomID) { result in
DispatchQueue.main.async {
switch result {
case .success(let fetchedPokemon):
pokemon = fetchedPokemon
case .failure(let error):
print("Error fetching Pokemon: \(error)")
}
}
}
}
}
This view contains a @State
property pokemon
to store the fetched Pokémon data. It includes a fetchPokemon
method triggered by a button press, initiating the API request to retrieve Pokémon data. Upon receiving the result from the apiManager
, it updates the UI with the fetched Pokémon or handles any encountered errors.
Conclusion
In the realm of Swift app development, integrating APIs and handling asynchronous data retrieval are essential skills. Through the exploration of a Pokémon-fetching sample app utilizing the PokeAPI, several fundamental concepts have been highlighted.