Skip to content

Instantly share code, notes, and snippets.

@pietrobasso
Last active January 17, 2022 14:49
Show Gist options
  • Save pietrobasso/a542bddd86dde2113b3be7686ce9c190 to your computer and use it in GitHub Desktop.
Save pietrobasso/a542bddd86dde2113b3be7686ce9c190 to your computer and use it in GitHub Desktop.
Throwable example usage!
import Foundation
// MARK: - Throwable
struct Throwable<T: Decodable>: Decodable {
private let result: Result<T, Error>
init(from decoder: Decoder) throws {
do {
result = .success(try T(from: decoder))
} catch let error {
// additionally, logError(error)
result = .failure(error)
}
}
func get() -> T? {
try? result.get()
}
}
// MARK: - Response
struct Response {
let items: [Widget]
}
extension Response: Decodable {
enum CodingKeys: CodingKey {
case items
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let items = try container
.decode([Throwable<Widget>].self, forKey: .items)
.compactMap { $0.get() }
guard !items.isEmpty else {
throw ResponseDecodingError.noWidgets
}
self.items = items
}
}
enum ResponseDecodingError: Error {
case noWidgets
}
// MARK: - Widget
enum Widget {
case headerWidget(HeaderWidget)
case cardWidget(CardWidget)
case buttonWidget(ButtonWidget)
}
extension Widget: Decodable {
enum `Type`: String, Decodable {
case headerWidget = "HeaderWidget"
case cardWidget = "CardWidget"
case buttonWidget = "ButtonWidget"
}
enum CodingKeys: String, CodingKey {
case type
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let type = try container.decode(`Type`.self, forKey: .type)
switch type {
case .headerWidget:
self = .headerWidget(try HeaderWidget(from: decoder))
case .cardWidget:
self = .cardWidget(try CardWidget(from: decoder))
case .buttonWidget:
self = .buttonWidget(try ButtonWidget(from: decoder))
}
}
}
// MARK: - Models
struct HeaderWidget: Decodable {
let title: String
let subtitle: String
}
struct CardWidget: Decodable {
let title: String
let image: URL
let operation: URL
}
struct ButtonWidget: Decodable {
let title: String
let operation: URL
}
let data: Data = """
{
"items": [
{
"type": "HeaderWidget",
"title": "Hello world",
"subtitle": "Lorem ipsum"
},
{
"type": "ChartWidget",
"title": "Your expenses path through the month",
"data": [3.72, 9.43, 13.72, 16.21, 25.04, 27.95]
},
{
"type": "CardWidget",
"title": "Your top visits",
"image": "www.example.com",
"operation": "app://purchase"
},
{
"type": "ButtonWidget",
"title": "Subscribe",
"operation": "app://subscribe"
}
]
}
""".data(using: .utf8)!
let response = try JSONDecoder().decode(Response.self, from: data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment