Skip to content

Instantly share code, notes, and snippets.

@stolton
Created October 7, 2023 21:22
Show Gist options
  • Save stolton/86ce14eb7dcf2b45d04532b84ef37b04 to your computer and use it in GitHub Desktop.
Save stolton/86ce14eb7dcf2b45d04532b84ef37b04 to your computer and use it in GitHub Desktop.
Pseudo Demo Code For Side Project Spotlight Episode #52
/*
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