API Basic To Advance in 9 Steps. Become Pro.

 API Basic To Advance in 9 Steps. Code Like Pro.


1. Basic API Call

A simple GET request using URLSession.

import Foundation
func basicGetRequest() { guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1") else { return } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in guard let data = data, error == nil else { print("Error:", error ?? "Unknown error") return } if let httpResponse = response as? HTTPURLResponse { print("Status Code: \(httpResponse.statusCode)") } if let result = try? JSONSerialization.jsonObject(with: data, options: []) { print("Result:", result) } } task.resume() }

2. Handling JSON with Decodable

Use Codable for type-safe JSON parsing.

import Foundation
struct Todo: Codable { let userId: Int let id: Int let title: String let completed: Bool } func fetchTodo() { guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1") else { return } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in guard let data = data, error == nil else { print("Error:", error ?? "Unknown error") return } do { let todo = try JSONDecoder().decode(Todo.self, from: data) print("Todo:", todo) } catch let decodingError { print("Decoding Error:", decodingError) } } task.resume() }

3. POST Request with JSON Body

Send a POST request with a JSON body.

import Foundation
struct User: Codable { let name: String let email: String } func createUser() { guard let url = URL(string: "https://jsonplaceholder.typicode.com/users") else { return } var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") let newUser = User(name: "John Doe", email: "john.doe@example.com") do { request.httpBody = try JSONEncoder().encode(newUser) } catch let encodingError { print("Encoding Error:", encodingError) return } let task = URLSession.shared.dataTask(with: request) { (data, response, error) in guard let data = data, error == nil else { print("Error:", error ?? "Unknown error") return } if let httpResponse = response as? HTTPURLResponse { print("Status Code: \(httpResponse.statusCode)") } if let result = try? JSONSerialization.jsonObject(with: data, options: []) { print("Result:", result) } } task.resume() }

4. Handling Errors and Status Codes

Use a custom error enum and handle different status codes.

import Foundation
enum NetworkError: Error { case badURL case requestFailed case unknown } func fetchData() { guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1") else { print(NetworkError.badURL) return } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in guard let data = data, error == nil else { print(NetworkError.requestFailed) return } if let httpResponse = response as? HTTPURLResponse { switch httpResponse.statusCode { case 200: print("Success:", httpResponse.statusCode) case 400...499: print("Client Error:", httpResponse.statusCode) case 500...599: print("Server Error:", httpResponse.statusCode) default: print("Unexpected Status Code:", httpResponse.statusCode) } } if let result = try? JSONSerialization.jsonObject(with: data, options: []) { print("Result:", result) } } task.resume() }

5. Using URLComponents to Build URLs with Query Parameters

For building complex URLs with query parameters.


import Foundation
func fetchTodos(userId: Int) { var urlComponents = URLComponents(string: "https://jsonplaceholder.typicode.com/todos")! urlComponents.queryItems = [URLQueryItem(name: "userId", value: "\(userId)")] guard let url = urlComponents.url else { return } let task = URLSession.shared.dataTask(with: url) { (data, response, error) in guard let data = data, error == nil else { print("Error:", error ?? "Unknown error") return } if let result = try? JSONSerialization.jsonObject(with: data, options: []) { print("Result:", result) } } task.resume() }

6. Advanced: API Call with Combine

Using the Combine framework for reactive programming.


import Foundation
import Combine struct Post: Codable { let id: Int let title: String let body: String } func fetchPost() -> AnyPublisher<Post, Error> { guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1") else { fatalError("Invalid URL") } return URLSession.shared.dataTaskPublisher(for: url) .map(\.data) .decode(type: Post.self, decoder: JSONDecoder()) .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } var cancellable: AnyCancellable? cancellable = fetchPost().sink(receiveCompletion: { completion in switch completion { case .finished: print("Finished") case .failure(let error): print("Error:", error) } }, receiveValue: { post in print("Post:", post) })

7. Advanced: API Call with Async/Await (Swift 5.5+)

Leverage Swift's async/await feature for more readable and concise asynchronous code.


import Foundation
@available(iOS 15.0, *) func fetchPostAsync() async { guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1") else { return } do { let (data, response) = try await URLSession.shared.data(for: URLRequest(url: url)) if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 { let post = try JSONDecoder().decode(Post.self, from: data) print("Post:", post) } } catch { print("Error:", error) } } @available(iOS 15.0, *) func exampleUsage() { Task { await fetchPostAsync() } }

8. Advanced: Handling Multipart Form Data

Upload files using multipart form data.

swift
import Foundation func uploadFile(fileUrl: URL, to url: URL) { var request = URLRequest(url: url) request.httpMethod = "POST" let boundary = UUID().uuidString request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") let data = createMultipartData(fileUrl: fileUrl, boundary: boundary) let task = URLSession.shared.uploadTask(with: request, from: data) { (data, response, error) in guard let data = data, error == nil else { print("Error:", error ?? "Unknown error") return } if let result = try? JSONSerialization.jsonObject(with: data, options: []) { print("Result:", result) } } task.resume() } func createMultipartData(fileUrl: URL, boundary: String) -> Data { var data = Data() let fileName = fileUrl.lastPathComponent let mimeType = "application/octet-stream" // Adjust based on your file type data.append("--\(boundary)\r\n".data(using: .utf8)!) data.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(fileName)\"\r\n".data(using: .utf8)!) data.append("Content-Type: \(mimeType)\r\n\r\n".data(using: .utf8)!) if let fileData = try? Data(contentsOf: fileUrl) { data.append(fileData) } data.append("\r\n".data(using: .utf8)!) data.append("--\(boundary)--\r\n".data(using: .utf8)!) return data }

9. Advanced: Handling API Calls with Dependency Injection

Using dependency injection for more testable and decoupled code.


import Foundation
protocol NetworkService { func fetchData(from url: URL, completion: @escaping (Result<Data, Error>) -> Void) } class APIService: NetworkService { func fetchData(from url: URL, completion: @escaping (Result<Data, Error>) -> Void) { let task = URLSession.shared.dataTask(with: url) { data, response, error in if let error = error { completion(.failure(error)) return } guard let data = data else { completion(.failure(NetworkError.unknown)) return } completion(.success(data)) } task.resume() } } class ViewModel { private let networkService: NetworkService init(networkService: NetworkService) { self.networkService = networkService } func loadData(from url: URL) { networkService.fetchData(from: url) { result in switch result { case .success(let data): print("Data received: \(data)") case .failure(let error): print("Error: \(error)") } } } } // Usage let viewModel = ViewModel(networkService: APIService()) viewModel.loadData(from: URL(string: "https://jsonplaceholder.typicode.com/todos/1")!)

Comments

Popular posts from this blog

Complete iOS Developer Guide - Swift 5 by @hiren_syl |  You Must Have To Know 😎 

Debugging

Swift Fundamentals You Can’t Miss! A List by @hiren_syl