This guide explains how to perform API calls in StarterAppKit, leveraging the NetworkManager
for asynchronous requests and Combine
for reactive data handling. StarterAppKit also integrates Alamofire to simplify HTTP networking.
StarterAppKit includes a NetworkManager
utility for managing API calls. It is designed to provide:
Combine
to handle responses reactively.The NetworkManager
handles all API calls and returns a Combine
publisher, making it easy to integrate with reactive Swift code.
me()
API CallThe me()
function is used to fetch the current user's profile data.
func me() -> AnyPublisher<(Int, Data), Error> { return Future<(Int, Data), Error> { [weak self] promise in guard let self = self else { promise(.failure(NetworkError.unknown)) return } Task { do { let accessToken = try await self.getValidAccessToken() let headers: HTTPHeaders = ["Authorization": "Bearer \(accessToken)"] AF.request(ApiEndpoints.baseurl + ApiEndpoints.user, method: .get, headers: headers).response { [weak self] response in switch response.result { case .success(let data): guard let data = data else { return } if let statusCode = response.response?.statusCode { if statusCode == 401 { self?.starterAppManager.signOut() } else { promise(.success((statusCode, data))) } } else { promise(.failure(AFError.responseValidationFailed(reason: .dataFileNil))) } case .failure(let error): promise(.failure(error)) } } } catch { promise(.failure(error)) } } } .eraseToAnyPublisher() }
Bearer
token to the request header.401
for unauthorized).Combine
's Future
to handle success and error states.API calls from the NetworkManager
are injected into your ViewModel
using the Factory
framework for dependency injection.
import Factory @Injected(\StarterAppContainer.networkManager) private var networkManager networkManager.me() .sink(receiveCompletion: { completion in switch completion { case .finished: print("Update completed successfully.") case .failure(let error): print("Failed to complete request: \(error.localizedDescription)") } }, receiveValue: { [weak self] statusCode, data in print(statusCode) self?.handleUserResponse(statusCode: statusCode, data: data) }) .store(in: &cancellables)
networkManager
is injected into the ViewModel
using Factory
.me()
function returns a publisher, making it easy to handle the response using sink
.receiveCompletion
handles errors or indicates when the operation is complete.receiveValue
closure updates the app state or UI in response to API results.Here’s how you can fetch and process user profile data in your ViewModel
:
import Factory import SwiftUI final class ExampleViewModel: ObservableObject { @Injected(\StarterAppContainer.networkManager) private var networkManager private var cancellables = Set<AnyCancellable>() @Published var userName: String = "" @Published var userEmail: String = "" func fetchUserProfile() { networkManager.me() .sink(receiveCompletion: { completion in switch completion { case .finished: print("User profile fetch completed successfully.") case .failure(let error): print("Failed to fetch user profile: \(error.localizedDescription)") } }, receiveValue: { [weak self] statusCode, data in guard let self = self else { return } self.parseUserProfileData(data: data) }) .store(in: &cancellables) } private func parseUserProfileData(data: Data) { do { let response = try JSONDecoder().decode(APIResponseModel.self, from: data) userName = response.user.firstName userEmail = response.user.emailAddress } catch { print("Failed to decode user profile data: \(error.localizedDescription)") } } }
Use Alamofire for Networking:
Dependency Injection:
Factory
to inject the NetworkManager
for clean, modular, and testable code.Error Handling:
401 Unauthorized
) gracefully.Combine Pipelines:
.sink
to process responses and completion states.Set<AnyCancellable>
to manage memory efficiently.Model Decoding:
Codable
) for easy integration into your app.