URLSession with async/await to make these calls without freezing the UI, and the Codable protocol to convert JSON into Swift structs.
Clients & Servers
A client is anything that asks for data—your iPhone, a laptop, a browser. A server is what answers. When you open Instagram, your phone (client) asks Instagram’s server for your feed, and the server sends back the posts.
Apps that rely on a server include social media, multiplayer games, and campus apps like Eatery. Apps that don’t need one—like the Camera app or Notes—work entirely on-device.
Key Takeaway
If your app shows data that lives somewhere else (another user's post, a menu, a leaderboard), it needs networking.
HTTP Requests
HTTP (HyperText Transfer Protocol) is the language clients and servers use to talk. A client sends a request, and the server sends back a response with a status code.
Request Methods
The four most common methods are GET (read data), POST (create data), PUT (update data), and DELETE (remove data). In this lecture we’ll focus on GET and POST.
Status Codes
Every HTTP response comes with a numeric status code. Here’s what each range means:
| Code | Category | What it means |
|---|---|---|
| 1XX | Info | Request received, still processing |
| 2XX | Success | Everything worked (200 OK is the most common) |
| 3XX | Redirect | Resource moved somewhere else |
| 4XX | Client Error | Something wrong with your request (404 = not found) |
| 5XX | Server Error | Server broke trying to handle a valid request |
JSON
JSON (JavaScript Object Notation) is the standard format for sending data over HTTP. It’s just key-value pairs—similar to a Swift dictionary. Keys are always strings; values can be strings, numbers, booleans, arrays, objects, or null.
{
"age": 19,
"classes": ["CS 1998", "PHYS 2213"],
"major": "Info Sci",
"name": "Vin Bui"
}
Notice how this maps almost directly to a Swift struct with properties age: Int, classes: [String], major: String, and name: String. That’s the whole idea—JSON is the bridge between the server’s data and your Swift model.
Networking in Swift
Why async/await?
Network requests take time—maybe milliseconds, maybe seconds. If we waited synchronously, the entire UI would freeze. Swift’s async/await (introduced in Swift 5.5) lets us “pause” a function in the background until the data arrives, without blocking the main thread.
Analogy
Think of it like ordering food at a restaurant. You place your order (send the request), then keep chatting with friends (the app stays responsive) until the waiter brings the food back (the response arrives).
A GET Request
Here’s the basic pattern for fetching data from a server:
func fetchPosts() async throws -> [Post] {
let url = URL(string: "https://api.example.com/posts")!
let (data, _) = try await URLSession.shared.data(from: url)
let posts = try JSONDecoder().decode([Post].self, from: data)
return posts
}
Three steps happen here:
1. Build a URL from a string. 2. Use URLSession.shared.data(from:) to fire the request and await the response. 3. Decode the raw Data into your Swift model with JSONDecoder.
Calling it from a View
struct FeedView: View {
@State private var posts: [Post] = []
var body: some View {
List(posts, id: \.username) { post in
Text("\(post.username) posted a new photo!")
}
.task {
do {
posts = try await fetchPosts()
} catch {
print("Failed to fetch posts: \(error)")
}
}
}
}
The .task modifier kicks off the async work when the view appears. Because it runs asynchronously, the list can render immediately (empty at first) and populate once the data arrives.
Codable
Codable is a protocol (actually a typealias for Decodable & Encodable) that tells Swift how to convert between JSON and your structs. If the JSON keys match your property names, you get automatic decoding for free:
struct Student: Codable {
let age: Int
let classes: [String]
let firstName: String
let lastName: String
let major: String
}
Watch Out: snake_case vs. camelCase
APIs often use snake_case keys (e.g. "first_name") while Swift uses camelCase (e.g. firstName). To handle this automatically, set the decoder’s key strategy:
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
Before Lecture
Come to lecture with a rough mental model of these ideas. You don’t need to memorize any syntax—we’ll live-code everything together and do a Postman demo so you can see making server requests in action. Some questions to think about::
Questions to Consider
1. What apps on your phone probably make HTTP requests? What data are they fetching?
2. If URLSession.shared.data(from:) is async, what would happen if it weren’t and you called it on the main thread?
3. Given a JSON object with keys "user_id" and "display_name", what would your Swift struct look like?