Working with APIs
By the end of this lesson you'll fetch real data from the internet with URLSession , turn JSON into Swift types with Codable , handle failures cleanly with do/try/catch , and show the result in a SwiftUI view — the skill that turns a static app into a live one.
Learn Working with APIs in our free Swift course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Swift course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ Codable — Turning JSON Into Swift Types
APIs speak JSON — plain text like {' "id": 1, "title": "Hello" '} . To use it, you describe its shape with a model (a struct ) and mark it Codable . That one word lets JSONDecoder read the text and fill in your struct automatically — every property name must match a JSON key, with the matching type. Read this worked example and run it; it needs no network.
2️⃣ URLSession + async/await — Fetching Over the Network
URLSession is Swift's built-in networking tool. The modern way to use it is async/await : you write try await URLSession.shared.data(from: url) and the line pauses until the bytes arrive, then carries on — reading top-to-bottom like ordinary code, with no nested callbacks. URL(string:) returns an Optional, so unwrap it safely, and remember URLSession only throws for transport errors — you check the HTTP status yourself.
Your turn. Below, the JSON and the calls are written for you — fill in the four ___ blanks marked with // 👉 to make the model and the decode work.
3️⃣ Error Handling — do / try / catch
Networking fails all the time — no signal, a typo in a URL, a server hiccup. Swift makes that explicit: a function that can fail is marked throws , you call it with try , and you wrap the call in do {' … '} catch {' … '} so a failure becomes a message instead of a crash. Inside catch , the thing that went wrong is available as error .
Now you try. This function is missing the three concurrency/error keywords. Fill in the three ___ blanks so it suspends, fetches, and handles failure.
4️⃣ Using the Data in SwiftUI with .task
A view that shows live data stores it in @State and loads it when it appears. The .task {' … '} modifier runs async code as the view shows up and cancels it automatically if the view disappears — so prefer it over .onAppear for loading. Code inside .task already runs on the main actor, so assigning to @State there updates the UI safely.
Sequential await calls wait for each other. When requests are independent, async let starts them all at once so the screen loads faster:
For snake_case APIs, skip hand-written CodingKeys with one line: decoder.keyDecodingStrategy = .convertFromSnakeCase maps first_name to firstName for the whole response.
📋 Quick Reference — Networking & JSON
No blanks this time — just a brief and an outline. Put together everything from this lesson: a Codable model, an async throws fetch, and a do/catch . Build it in Xcode and check your output against the expected line in the comments.
This was the final Swift lesson. Here's what you can now do:
Where to go next: wire this into a real app idea. Persist data with SwiftData or Core Data, add pull-to-refresh and loading states, structure logic into an MVVM view model, then publish to TestFlight . Practise by building a weather, news, or GitHub-search app against a free public API — you now have every piece you need.
Practice quiz
Which protocol lets a struct map to and from JSON?
- Codable
- Serializable
- JSONMappable
- Decoder
Answer: Codable. Conforming to Codable enables automatic JSON encoding and decoding.
Which type reads JSON bytes into a Swift value?
- JSONReader
- JSONDecoder
- JSONParser
- Decoder.shared
Answer: JSONDecoder. JSONDecoder().decode(...) turns Data into your model.
Which keyword marks a function that can pause for async work?
- throws
- defer
- async
- lazy
Answer: async. async marks a function that can suspend while awaiting results.
What does await do in a networking call?
- Throws an error
- Declares a constant
- Retries the request
- Suspends until the result arrives
Answer: Suspends until the result arrives. await pauses the function until the async result is ready.
Does URLSession throw an error on a 404 response?
- No, you must check the status code yourself
- Yes, always
- Only on 500
- Only without internet
Answer: No, you must check the status code yourself. URLSession only throws for transport errors; check statusCode == 200 yourself.
Which construct handles a thrown error safely?
- if let / else
- do / try / catch
- guard / return
- switch / default
Answer: do / try / catch. do { try ... } catch { ... } catches errors instead of crashing.
What does URL(string:) return?
- A String
- A Data value
- An Optional URL
- An error
Answer: An Optional URL. URL(string:) is failable and returns an optional, so unwrap it safely.
Which keyword marks a call inside catch-able code that may fail?
- catch
- async
- await
- try
Answer: try. try marks the exact call that may throw an error.
Which SwiftUI modifier runs async loading when a view appears?
- .task
- .onTap
- .refreshable
- .async
Answer: .task. .task runs async code on appear and auto-cancels on disappear.
What do you pass to decode to name the target type?
- Post()
- Post
- Post.self
- "Post"
Answer: Post.self. Pass the type itself, e.g. Post.self, to JSONDecoder().decode.