Skip to main content

Networking and Basic Codables

This snippet demonstrates how to structure API endpoints and implement a networking layer in Swift, ensuring scalability and maintainability.

Details

URL: 🔗 Networking and Basic Codables

Source: 🔗 Ace the iOS Interview

Author: Aryaman Sharda

Tags:
Swift, Networking, Codables, URLSession

Platforms Supported: iOS, macOS

Swift Version: 5.0 and above

Key Points​

  • Introduces enums for HTTP methods and schemes.
  • Defines a protocol to represent API endpoints.
  • Implements a generic networking layer.
  • Provides an example with the Google Places API.

Use Cases​

  • Standardizing API requests across different services.
  • Simplifying network call implementation and maintenance.
  • Decoupling URL construction from request execution.

Alternative Approaches​

  • Using third-party libraries like Alamofire for more advanced networking needs.
  • Directly using URLSession without abstracting API endpoints.
  • Employing a service-oriented architecture to manage API calls.

Performance Considerations​

  • Ensures reusability and reduces boilerplate code.
  • Abstraction adds a small overhead but increases maintainability.
  • Properly handles threading and asynchronous tasks.

Code​

import Foundation

// Enum for HTTP Methods
enum HTTPMethod: String {
case delete = "DELETE"
case get = "GET"
case patch = "PATCH"
case post = "POST"
case put = "PUT"
}

// Enum for HTTP Schemes
enum HTTPScheme: String {
case http
case https
}

// Protocol to represent API endpoints
protocol API {
var scheme: HTTPScheme { get }
var baseURL: String { get }
var path: String { get }
var parameters: [URLQueryItem] { get }
var method: HTTPMethod { get }
}

// Example implementation for Google Places API
enum GooglePlacesAPI: API {
case getNearbyPlaces(searchText: String?, latitude: Double, longitude: Double)

var scheme: HTTPScheme {
return .https
}

var baseURL: String {
return "maps.googleapis.com"
}

var path: String {
return "/maps/api/place/nearbysearch/json"
}

var parameters: [URLQueryItem] {
switch self {
case .getNearbyPlaces(let query, let latitude, let longitude):
var params = [
URLQueryItem(name: "key", value: "YOUR_API_KEY"),
URLQueryItem(name: "language", value: Locale.current.languageCode),
URLQueryItem(name: "type", value: "restaurant"),
URLQueryItem(name: "radius", value: "6500"),
URLQueryItem(name: "location", value: "\(latitude),\(longitude)")
]
if let query = query {
params.append(URLQueryItem(name: "keyword", value: query))
}
return params
}
}

var method: HTTPMethod {
return .get
}
}

// Networking layer to handle requests and responses
final class NetworkManager {
fileprivate class func buildURL(endpoint: API) -> URLComponents {
var components = URLComponents()
components.scheme = endpoint.scheme.rawValue
components.host = endpoint.baseURL
components.path = endpoint.path
components.queryItems = endpoint.parameters
return components
}

class func request<T: Codable>(endpoint: API, completion: @escaping (Result<T, Error>) -> Void) {
var urlRequest = URLRequest(url: buildURL(endpoint: endpoint).url!)
urlRequest.httpMethod = endpoint.method.rawValue

let task = URLSession.shared.dataTask(with: urlRequest) { data, response, error in
if let error = error {
completion(.failure(error))
return
}

guard let data = data else {
// Handle missing data error
return
}

do {
let decodedResponse = try JSONDecoder().decode(T.self, from: data)
completion(.success(decodedResponse))
} catch {
completion(.failure(error))
}
}

task.resume()
}
}

References​

Read Full Snippet→