NS

Fetch data from APIs in SwiftUI

SwiftUI

SwiftUI is an innovative, exceptionally simple way to build user interfaces across all Apple platforms with the power of Swift. Build user interfaces for any Apple device using just one set of tools and APIs. — Wikipedia. The best part is, you can integrate your views with components from UIKit, AppKit and WatchKit framework. SwiftUI has made building user interface straightforward.

APIs

API stands for Application Programming Interface. At some point, you would have built or will build APIs for your app. API allows your application to communicate to the server. One most important point to note is, API is just an interface between your application and the server/database. It is not a database or server itself. It just allows all these entities to talk to each other. In simple words, API is an access point to your job that can access different entities such as a server or a database etc. For example, the weather has an API that you could use, that does not mean you have access to their database and can query everything. You only have access to an access point that has access to the database. I get this question a lot and figured I would spend 2–3 lines specifically addressing this.

In this article, we will talk about how you could fetch data in SwiftUI from an API. Let us get started by creating a new project.

  1. Open Xcode
  2. Create a new project (Single View Application is alright)
  3. Make sure Use SwiftUI is selected under languages

Alright! Now we have a project setup, you could see ContentView.swift in your project structure. Try running your code, you should be able to see “Hello World” string printed on your iPhone

Model: Create a new Swift file and name it Model.swift. We need a struct “TaskEntry” to store fetched data into and another TaskList to Store fetchedResponse. Let’s create a simple model

import Foundationstruct TaskEntry: Codable  {  
    let id: Int  
    let title: String  
}

Codable: Usually APIs return a JSON and you would need to decode and encode using JSONEncoder and JSONDecoder, therefore, we need to make sure our model can be coded and decoded. Therefore, we have added “Codable” string to make the Model codable.

Service: Go back to your Content View and add a new State variable,

//Since the response is an array of TaskEntry object  
@State var results = \[TaskEntry\]()

In your ContentView.swift, create a new Function to load data

        guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos") else {
            print("Invalid URL")
            return
        }
        let request = URLRequest(url: url)

        URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data {
                if let response = try? JSONDecoder().decode([TaskEntry].self, from: data) {
                    DispatchQueue.main.async {
                        self.results = response
                    }
                    return
                }
            }
        }.resume()
    }

This function will load our data into our struct. If at this point, you would print your data in init(), you should be able to see your API response. Run your program and you should be able to see all the data from your API printed in the console. Alright! Milestone 1 completed. Your service is hitting your end-point correctly and encoding decoding is working perfectly too while reading data from your API.

Now let us render this data on the screen. To do that, we need to call the function loadData(). One thing I love about SwiftUI is the built-in modifiers, such as “.onAppear”. Lets’ go ahead and add a modifier to our list so as our list appears, we call loadData() and create our View.


struct ContentView: View {
    
    @State var results = [TaskEntry]()
  
    var body: some View {
        List(results, id: \.id) { item in
            VStack(alignment: .leading) {
                Text(item.title)
            }
        }.onAppear(perform: loadData)
    }
    
  
    func loadData() {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos") else {
            print("Your API end point is Invalid")
            return
        }
        let request = URLRequest(url: url)

        URLSession.shared.dataTask(with: request) { data, response, error in
            if let data = data {
                if let response = try? JSONDecoder().decode([TaskEntry].self, from: data) {
                    DispatchQueue.main.async {
                        self.results = response
                    }
                    return
                }
            }
        }.resume()
    }
    
}

Go ahead and run your app. You should be able to see the fetched data from your API. That is it! Your SwiftUI app is now communicating with your API. You can find the boiler-plate to start with on my Github. Thank you !