-
-
Save stolton/86ce14eb7dcf2b45d04532b84ef37b04 to your computer and use it in GitHub Desktop.
Pseudo Demo Code For Side Project Spotlight Episode #52
This file contains 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
/* | |
http://phillycocoa.org/podcast/sps-52/ | |
DISCLAIMER: This is not the actual code Steve is talking about. | |
He wrote this in TextEdit while waiting for the podcast recordings to render to provide an | |
illustration based on our discussion. | |
It's untested, even by the Swift compiler! Not meant for real-world use! | |
This is just to help you visualize what Steve is rambling about in this episode. | |
*/ | |
protocol Resource { | |
var httpMethod: String { get } | |
var baseUrl: String { get } | |
var path: String { get } | |
var parameters: [String: String]? | |
func urlRequest() throws -> URLRequest | |
} | |
extension Resource { | |
var httpMethod: String { "GET" } | |
var parameters: [String: String]? { nil } | |
var baseUrl: String { | |
return "https://backyardsquirrels.demo/api" | |
} | |
func urlRequest() throws -> URLRequest { | |
var components = URLComponents(url: baseUrl, resolvingAgainstBaseURL: false) | |
components?.path += path | |
if let params = self.parameters { | |
components?.queryItems = params.map { key, value in | |
URLQueryItem(name: key, value: "\(value)") | |
} | |
} | |
guard let url = components?.url else { | |
// Throw error | |
} | |
var urlRequest = URLRequest(url: url) | |
urlRequest.httpMethod = httpMethod | |
return urlRequest | |
} | |
} | |
protocol Transport { | |
func fetch(request: URLRequest) async throws -> Data | |
} | |
enum API { | |
enum BackyardSquirrels { | |
case getNuts(numberOfNuts: String) | |
} | |
} | |
extension API.BackyardSquirrels: Resource { | |
var path: String { | |
switch self { | |
case .getNuts: | |
return "/nuts" | |
} | |
} | |
var parameters: [String: String]? { | |
switch self { | |
case .getNuts(let numberOfNuts): | |
return ["numberOfNuts": numberOfNuts] | |
} | |
} | |
} | |
struct ApiClient { | |
let transport: Transport | |
func fetch<Model: Decodable>(_: Model.Type, from resource: Resource) async throws -> Model { | |
let data = try await transport.fetch(resource.urlRequest()) | |
let model = JSONDecoder().decode(Model.self, from: data) | |
return model | |
} | |
} | |
extension URLSession: Transport { | |
func fetch(request: URLRequest) async throws -> Data { | |
// Implement your request logic here using self.data(for: request) | |
// ... | |
} | |
} | |
struct Nut { // ... } | |
@Observable | |
struct BackyardSquirrelsModel { | |
let apiClient = ApiClient(transport: URLSession.shared) | |
var nuts: [Nut]? | |
// ... | |
func loadNuts() async throws { | |
nuts = try await apiClient.fetch([Nut].Self, from: API.BackyardSquirrels.getNuts(numberOfNuts: "2")) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment