Skip to content

Instantly share code, notes, and snippets.

@mrugeshtank
Last active December 13, 2022 07:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrugeshtank/4ba6a3fca46e88bb229c4ca48daafd35 to your computer and use it in GitHub Desktop.
Save mrugeshtank/4ba6a3fca46e88bb229c4ca48daafd35 to your computer and use it in GitHub Desktop.
This file is a walkthrough of an article by Donny Wals at https://www.donnywals.com/architecting-a-robust-networking-layer-with-protocols/
import Foundation
struct Feed: Decodable {
}
class FeedViewModel {
let service: FeedProviding
var feed: Feed?
var onFeedUpdate: () -> Void = {}
init(service: FeedProviding) {
self.service = service
}
func fetch() {
service.getFeed { result in
do {
self.feed = try result.get()
self.onFeedUpdate()
} catch {
// handle error
}
}
}
}
protocol FeedProviding {
var network: Networking { get }
func getFeed(_ completion: @escaping (Result<Feed, Error>) -> Void)
}
extension FeedProviding {
func getFeed(_ completion: @escaping (Result<Feed, Error>) -> Void) {
network.execute(Endpoint.feed, completion: completion)
}
}
protocol Networking {
func execute<T: Decodable>(_ requestProvider: Endpoint, completion: @escaping (Result<T, Error>) -> Void)
}
enum Endpoint {
case feed
}
extension Networking {
func execute<T: Decodable>(_ requestProvider: Endpoint, completion: @escaping (Result<T, Error>) -> Void) {
let urlRequest = requestProvider.urlRequest
URLSession.shared.dataTask(with: urlRequest) { data, response, error in
do {
if let error = error {
completion(.failure(error))
return
}
guard let data = data else {
preconditionFailure("No error was received but we also don't have data...")
}
let decodedObject = try JSONDecoder().decode(T.self, from: data)
completion(.success(decodedObject))
} catch {
completion(.failure(error))
}
}.resume()
}
}
protocol RequestProviding {
var urlRequest: URLRequest { get }
}
extension Endpoint: RequestProviding {
var urlRequest: URLRequest {
switch self {
case .feed:
guard let url = URL(string: "https://mydomain.com/feed") else {
preconditionFailure("Invalid URL used to create URL instance")
}
return URLRequest(url: url)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment