Networking: calling an API from Swift
Learn async/await and URLSession — the foundation you'll need to call an AI model over the network in Module 5.
Your AI feature will call a model hosted on the internet. That means networking — sending an HTTP request and awaiting a response. Modern Swift makes this readable with async/await: code that waits for the network without freezing the UI.
The shape of every network call
import Foundation
struct Quote: Decodable {
let quote: String
let author: String
}
func fetchQuote() async throws -> Quote {
let url = URL(string: "https://dummyjson.com/quotes/random")!
let (data, response) = try await URLSession.shared.data(from: url)
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else {
throw URLError(.badServerResponse)
}
return try JSONDecoder().decode(Quote.self, from: data)
}Read it top to bottom: build a URL, await the data (execution pauses here without blocking the screen), check the HTTP status, then decode the JSON into a Swift struct. Decodable means Swift maps JSON fields onto struct properties automatically — this API returns {"id": …, "quote": "…", "author": "…"}, and your struct declares only the fields it cares about; the decoder ignores the rest. Almost every API call you ever write is a variation of this.
Calling it from a view
struct QuoteView: View {
@State private var quote: Quote?
@State private var isLoading = false
var body: some View {
VStack {
if let quote { Text(quote.quote) }
Button("Get quote") {
Task { await load() } // Task bridges sync UI to async work
}
}
}
private func load() async {
isLoading = true
defer { isLoading = false }
quote = try? await fetchQuote()
}
}Button actions are synchronous, but network calls are async. Task { await … } starts an asynchronous unit of work from synchronous code. You'll use this exact bridge every time a tap triggers a network request.
1) Forgetting try/await — the compiler will remind you. 2) A Decodable struct whose field names don't match the JSON — decoding throws. 3) Doing UI updates off the main thread — in modern SwiftUI, keep state changes in the view's context and you're fine.