Bird
Raised Fist0
iOS Swiftmobile~20 mins

GET request with async/await in iOS Swift - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Simple GET Request
This screen fetches a random joke from an online API and shows it on the screen when you tap the button.
Target UI
-------------------------
| Simple GET Request     |
|-----------------------|
|                       |
|  [ Joke will appear   ]|
|  [ here after fetch ]  |
|                       |
|  [ Fetch Joke Button ] |
-------------------------
Add a button labeled 'Fetch Joke' at the bottom center.
When tapped, perform an async GET request to https://official-joke-api.appspot.com/random_joke.
Parse the JSON response to get the joke's setup and punchline.
Display the joke text in the center area.
Show a loading indicator while fetching.
Handle errors by showing an alert with a friendly message.
Starter Code
iOS Swift
import SwiftUI

struct ContentView: View {
    @State private var jokeText = "Press the button to fetch a joke."
    @State private var isLoading = false
    @State private var showAlert = false
    @State private var alertMessage = ""

    var body: some View {
        VStack {
            Spacer()
            Text(jokeText)
                .multilineTextAlignment(.center)
                .padding()
            Spacer()
            if isLoading {
                ProgressView()
                    .padding()
            }
            Button("Fetch Joke") {
                // TODO: Add async GET request here
            }
            .padding()
        }
        .alert(isPresented: $showAlert) {
            Alert(title: Text("Error"), message: Text(alertMessage), dismissButton: .default(Text("OK")))
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Task 1
Task 2
Task 3
Task 4
Task 5
Task 6
Solution
iOS Swift
import SwiftUI

struct Joke: Decodable {
    let setup: String
    let punchline: String
}

struct ContentView: View {
    @State private var jokeText = "Press the button to fetch a joke."
    @State private var isLoading = false
    @State private var showAlert = false
    @State private var alertMessage = ""

    var body: some View {
        VStack {
            Spacer()
            Text(jokeText)
                .multilineTextAlignment(.center)
                .padding()
            Spacer()
            if isLoading {
                ProgressView()
                    .padding()
            }
            Button("Fetch Joke") {
                Task {
                    await fetchJoke()
                }
            }
            .padding()
        }
        .alert(isPresented: $showAlert) {
            Alert(title: Text("Error"), message: Text(alertMessage), dismissButton: .default(Text("OK")))
        }
    }

    func fetchJoke() async {
        isLoading = true
        defer { isLoading = false }

        guard let url = URL(string: "https://official-joke-api.appspot.com/random_joke") else {
            alertMessage = "Invalid URL."
            showAlert = true
            return
        }

        do {
            let (data, response) = try await URLSession.shared.data(from: url)

            guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
                alertMessage = "Server error."
                showAlert = true
                return
            }

            let joke = try JSONDecoder().decode(Joke.self, from: data)
            jokeText = "\(joke.setup)\n\n\(joke.punchline)"
        } catch {
            alertMessage = "Failed to fetch joke. Please try again."
            showAlert = true
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

This solution uses SwiftUI with async/await to fetch a joke from the API.

We define a Joke struct matching the JSON fields setup and punchline.

The fetchJoke() function is marked async and uses URLSession.shared.data(from:) with await to perform the GET request.

We check the HTTP response code to ensure success, then decode the JSON data into a Joke instance.

The joke text is updated on the main thread by changing the jokeText state variable.

Loading state is managed with isLoading to show a spinner while fetching.

Errors show an alert with a friendly message.

The button triggers the async fetch inside a Task to run asynchronously.

Final Result
Completed Screen
-------------------------
| Simple GET Request     |
|-----------------------|
|                       |
|  Why did the chicken  |
|  cross the road?      |
|                       |
|  To get to the other  |
|  side!                |
|                       |
|  [ Fetch Joke Button ] |
-------------------------
User taps 'Fetch Joke' button.
A spinner appears below the joke text while loading.
After a moment, the joke text updates with the fetched joke.
If an error occurs, an alert pops up with an error message.
Stretch Goal
Add a pull-to-refresh gesture to fetch a new joke.
💡 Hint
Use SwiftUI's .refreshable modifier on the VStack and call fetchJoke() inside it.

Practice

(1/5)
1. What does the async keyword indicate in a Swift function that performs a GET request?
easy
A. The function is synchronous and blocks the main thread.
B. The function runs asynchronously and can be awaited.
C. The function automatically retries on failure.
D. The function only works with POST requests.

Solution

  1. Step 1: Understand async keyword meaning

    The async keyword means the function runs asynchronously, allowing other code to run while waiting.
  2. Step 2: Connect async with await usage

    Functions marked async can be called with await to pause until the result is ready without blocking.
  3. Final Answer:

    The function runs asynchronously and can be awaited. -> Option B
  4. Quick Check:

    async means asynchronous function [OK]
Hint: async means function can be paused with await [OK]
Common Mistakes:
  • Thinking async means synchronous/blocking
  • Confusing async with retry logic
  • Assuming async only applies to POST requests
2. Which of the following is the correct syntax to perform a GET request using async/await in Swift?
easy
A. let (data, _) = try await URLSession.shared.data(from: url)
B. let data = URLSession.shared.dataTask(with: url)
C. let data = await URLSession.shared.data(from: url)
D. let (data, response) = URLSession.shared.data(from: url)

Solution

  1. Step 1: Identify correct async/await syntax

    The correct syntax uses try await with URLSession.shared.data(from:) to get data and response.
  2. Step 2: Check tuple unpacking

    The method returns a tuple of (Data, URLResponse), so unpacking with (data, _) is correct if response is unused.
  3. Final Answer:

    let (data, _) = try await URLSession.shared.data(from: url) -> Option A
  4. Quick Check:

    Use try await with data(from:) [OK]
Hint: Use try await with data(from:) and unpack tuple [OK]
Common Mistakes:
  • Omitting try keyword
  • Using dataTask without await
  • Not unpacking the returned tuple
3. Given the code below, what will be printed if the GET request succeeds?
func fetchData() async {
  let url = URL(string: "https://example.com/data.json")!
  do {
    let (data, _) = try await URLSession.shared.data(from: url)
    print("Data length: \(data.count)")
  } catch {
    print("Failed to fetch")
  }
}
medium
A. Syntax error
B. Failed to fetch
C. Data length: 0
D. Data length: [number of bytes in data]

Solution

  1. Step 1: Analyze successful GET request

    If the request succeeds, try await returns data and response without throwing an error.
  2. Step 2: Understand print statement output

    The code prints the length of the received data in bytes, so output is "Data length: [number]".
  3. Final Answer:

    Data length: [number of bytes in data] -> Option D
  4. Quick Check:

    Success prints data length [OK]
Hint: Success prints data length, failure prints error [OK]
Common Mistakes:
  • Assuming print shows raw data
  • Confusing catch block output
  • Expecting zero length on success
4. Identify the error in this Swift async GET request code:
func load() async {
  let url = URL(string: "https://api.example.com")!
  let (data, response) = URLSession.shared.data(from: url)
  print(String(data: data, encoding: .utf8) ?? "No data")
}
medium
A. Incorrect print statement syntax
B. URL is invalid
C. Missing await keyword before URLSession.shared.data(from: url)
D. Missing try keyword before URLSession.shared.data(from: url)

Solution

  1. Step 1: Check async call usage

    The method data(from:) is async and must be awaited with await.
  2. Step 2: Confirm missing await keyword

    The code calls URLSession.shared.data(from: url) without await, causing a compile error.
  3. Final Answer:

    Missing await keyword before URLSession.shared.data(from: url) -> Option C
  4. Quick Check:

    Async calls require await [OK]
Hint: Async calls always need await keyword [OK]
Common Mistakes:
  • Forgetting await on async calls
  • Assuming try is optional
  • Misreading URL validity
5. You want to fetch JSON data from a URL and decode it into a Swift struct using async/await. Which code snippet correctly performs the GET request and decodes the data?
struct User: Decodable {
  let id: Int
  let name: String
}

func fetchUser() async throws -> User {
  let url = URL(string: "https://api.example.com/user")!
  // Which code goes here?
}
hard
A. let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode(User.self, from: data)
B. let data = try URLSession.shared.data(from: url) return JSONDecoder().decode(User.self, from: data)
C. let (data, _) = URLSession.shared.data(from: url) return try JSONDecoder().decode(User.self, from: data)
D. let (data, _) = try await URLSession.shared.dataTask(with: url) return try JSONDecoder().decode(User.self, from: data)

Solution

  1. Step 1: Use async/await with data(from:)

    The correct async call is try await URLSession.shared.data(from: url) which returns data and response.
  2. Step 2: Decode JSON data into struct

    Use JSONDecoder().decode(User.self, from: data) to convert JSON bytes into the User struct.
  3. Final Answer:

    let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode(User.self, from: data) -> Option A
  4. Quick Check:

    Use try await with data(from:) and decode JSON [OK]
Hint: Use try await data(from:) then decode JSON [OK]
Common Mistakes:
  • Using dataTask instead of data(from:)
  • Omitting await or try keywords
  • Not decoding JSON properly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard