SwiftUI – How to call a Rest API with Combine

In this post, we will see how to consume a Rest API in Swift with Combine.
We will use a Rest API that it will get us the list of the annual holiday for Italy in 2022.

But first of all, what is Combine?
From Apple web site:
“The Combine framework provides a declarative Swift API for processing values over time. These values can represent many kinds of asynchronous events. Combine declares publishers to expose values that can change over time, and subscribers to receive those values from the publishers.”

We open Xcode and we create a new iOS app called TestWebAPI where we will define our MVVM components:

[Model – Holiday.swift]

import Foundation

// Codable -> it allows us to serialize Json data in this struct
struct Holiday:  Codable 
{
    var date: String
    var localName: String
    var countryCode: String
}


[View Model – CoreData.swift]

import Foundation

// ObservableObject -> it allows us to define an observable object (Holidays)
class CoreData: ObservableObject {
    
    // url service
    let url = URL(string: "https://date.nager.at/api/v2/publicholidays/2022/it")
    
    // variable used to store the list of holidays
    @Published var Holidays = [Holiday]()
    
    func GetHoliday()
    {
        // here we create a publisher that’ll emit a value when its data task succeeds (or fails)
        URLSession.shared.dataTaskPublisher(for: url!)
            // After we had the data, we will decode it into an array of Holiday
            .map { $0.data }
            .decode(type: [Holiday].self, decoder: JSONDecoder())
            // It will replace any errors in the stream with the provided element.
            .replaceError(with: [])
            // it will erase the type of the upstream publisher
            .eraseToAnyPublisher()
            // Since the data needs to be rendered on UI, we want to receive it on the MainThread.
            .receive(on: DispatchQueue.main)
            // It assigns the result at our array called Holidays
            .assign(to: &$Holidays)
    }
}


[View – ContentView.swift]

import SwiftUI

struct ContentView: View {
    // we define viewModel as an observedObject
    @ObservedObject var viewModel = CoreData()
    var body: some View {
        NavigationView{
            List(viewModel.Holidays, id: \.date){item in
                VStack(alignment: .leading)
                {
                    Text("\(item.localName)")
                        .font(.system(size: 20, weight: .bold))
                        .foregroundColor(.blue)
                        .padding(.bottom)
                    
                    HStack{
                        Text("\(item.date)")
                            .font(.body)
                            .fontWeight(.bold)
                        Spacer()
                        Text("\(item.countryCode)")
                            .font(.body)
                            .foregroundColor(.red)
                    }
                }
            }.navigationBarTitle("Italy Holidays - 2022")
                        .onAppear {
                            // when it appears, app will call GetHoliday method
                            self.viewModel.GetHoliday()
                        }
        }
    }
}

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


We have done and if we run the application, this will be the result: