Fetch and decode JSON with async/await and URLSession
modern networking basics.
call URLSession.shared.data(from:) inside an async throws function, check the HTTPURLResponse status, then JSONDecoder().decode([User].self) and let errors propagate via try.
What's really being asked
This confirms fluency with Swift structured concurrency and Codable, plus disciplined error handling. It is a baseline competency check for any iOS role touching networking.
The full answer
Define an async throws function so both suspension and failure are explicit. Use the async URLSession API: let (data, response) = try await URLSession.shared.data(from: url). This throws on transport failures like no connectivity. Then validate the response by casting to HTTPURLResponse and confirming the statusCode is in the 200 to 299 range, throwing a custom error otherwise, because a 404 or 500 still returns data and would otherwise be decoded as if successful. Decode with let users = try JSONDecoder().decode([User].self, from: data), where User is a struct conforming to Codable whose properties match the JSON, optionally with a keyDecodingStrategy. Errors flow up through try, so the caller wraps the call in do/catch and can distinguish URLError, the custom HTTP error, and DecodingError. Avoid force unwrapping the cast or the URL.
The mistakes people make
Decoding immediately without checking the HTTP status, so error payloads are misread. Force-casting the response or force-unwrapping data. Catching errors and returning an empty array, hiding failures. Mixing completion handlers with async/await unnecessarily.
What usually comes next
How do you cancel an in-flight request? Where does Task fit in? How do you map snake_case keys? How would you add a timeout or retry?
A concrete example
func fetchUsers() async throws -> [User] awaits the data call, guards that the HTTPURLResponse status is in 200..<300 else throws APIError.badStatus, then returns try JSONDecoder().decode([User].self, from: data). The caller writes do { let users = try await fetchUsers() } catch { handle the error }, cleanly separating success from each failure category without force unwraps.
Interview question
Using URLSession's async data(from:), why should you inspect the HTTPURLResponse status code before decoding the body?
- a.Because the status code must be passed to the decoder
- b.Because JSONDecoder cannot run on the main thread
- c.Because data(from:) does not throw on connectivity errors
- d.Because a 4xx or 5xx response still returns a body that would otherwise be decoded as if the request succeededCorrect
Why? this is the answer
Error responses like 404 or 500 still deliver a body, so without checking the status you may decode an error payload as a success and mislead callers. data(from:) does throw on transport errors, and the decoder needs no status code.
Just read this? Test yourself on what you have been reading.
Read the original → developer.apple.com
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on ios — each one lists the topics its interview covers.
See open roles