Created
February 10, 2026 18:34
-
-
Save codewithsanthoshofficial/f8e446da2e628c0aa6c799d29f71629f to your computer and use it in GitHub Desktop.
SwiftUI_apiCall_Combine
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Foundation | |
| import Combine | |
| enum HttpMethod:String { | |
| case get = "GET" | |
| case post = "POST" | |
| case put = "PUT" | |
| case delete = "DELETE" | |
| } | |
| enum NetworkError:Error { | |
| case invlaidURL | |
| case serverError(Int) | |
| case decodingError | |
| case unknown | |
| } | |
| class APIService { | |
| static let shared = APIService() | |
| private init(){ } | |
| func request<T:Codable>(endpoint:String, method:HttpMethod = .get, headers: [String: String]? = nil, parameters: [String: Any]? = nil) -> AnyPublisher<T, Error> { | |
| guard let url = URL(string: endpoint) else { | |
| return Fail(error: NetworkError.invlaidURL).eraseToAnyPublisher() | |
| } | |
| var request = URLRequest(url: url) | |
| request.httpMethod = method.rawValue | |
| headers?.forEach { | |
| request.addValue($0.value, forHTTPHeaderField: $0.key) | |
| } | |
| if let parameters { | |
| request.httpBody = try? JSONSerialization.data(withJSONObject: parameters) | |
| request.addValue("application/json", forHTTPHeaderField: "Content-Type") | |
| } | |
| let urlsession = URLSession.shared.dataTaskPublisher(for: request) | |
| // 1. Check for HTTP status codes | |
| .tryMap { output in | |
| guard let response = output.response as? HTTPURLResponse, (200...299).contains(response.statusCode) else { | |
| throw NetworkError.serverError((output.response as? HTTPURLResponse)?.statusCode ?? 500) | |
| } | |
| return output.data | |
| } | |
| // 2. Decode the JSON | |
| .decode(type: T.self, decoder: JSONDecoder()) | |
| // 3. Move back to the Main Thread for UI updates | |
| .receive(on: DispatchQueue.main) | |
| // 4. Erase type to make it reusable | |
| .eraseToAnyPublisher() | |
| return urlsession | |
| } | |
| } | |
| ========= | |
| import Foundation | |
| enum APIEndPoint { | |
| static let baseURL = "https://newsapi.org/v2/everything?q=tesla&from=2026-01-10&sortBy=publishedAt&apiKey=" | |
| case news | |
| var url:String { | |
| switch self { | |
| case .news : return "\(APIEndPoint.baseURL)" | |
| } | |
| } | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Foundation | |
| import Combine | |
| class NewsViewModel:ObservableObject { | |
| @Published var newList:[Articles] = [] | |
| @Published var errorMessage:String? | |
| @Published var showError:Bool = false | |
| // This stores your subscriptions so they don't get cancelled immediately | |
| private var cancellables = Set<AnyCancellable>() | |
| init() { | |
| getNews() | |
| } | |
| func getNews() { | |
| let publisher: AnyPublisher<NewsModelRes, Error> = APIService.shared.request(endpoint: APIEndPoint.news.url) | |
| //Publisher: URLSession starts the data flow. | |
| publisher | |
| .receive(on: DispatchQueue.main) | |
| // Specifying the type we expect (NewsResponse) | |
| .sink { [weak self] completion in | |
| switch completion { | |
| case .finished: | |
| break // Do nothing on success | |
| case .failure(let error): | |
| self?.errorMessage = error.localizedDescription | |
| self?.showError = true | |
| } | |
| } receiveValue: { [weak self] response in | |
| // This only runs if the request succeeds | |
| self?.newList = response.articles ?? [] | |
| } | |
| .store(in: &cancellables) // Keep the subscription alive | |
| } | |
| } | |
| //POST | |
| //let response:NewsModelRes = try await APIService.shared.request(endpoint: APIEndPoint.news.url, method: .put, headers: nil, parameters: [:]) | |
| =================== | |
| import Foundation | |
| struct NewsModelRes:Codable { | |
| let status:String? | |
| let totalResults:Int? | |
| let articles:[Articles]? | |
| enum CodingKeys: String, CodingKey { | |
| case status | |
| case totalResults | |
| case articles | |
| } | |
| } | |
| struct Articles:Codable, Identifiable { | |
| var id : String {url ?? ""} | |
| let author: String? | |
| let title: String? | |
| let description: String? | |
| let url: String? | |
| let urlToImage: String? | |
| enum CodingKeys: String, CodingKey { | |
| case author | |
| case title | |
| case description | |
| case url | |
| case urlToImage | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment