Skip to content

Instantly share code, notes, and snippets.

@mattpolzin
Last active June 30, 2020 05:04
Show Gist options
  • Save mattpolzin/1b98a22642e46387f6b867fd4e5e37c8 to your computer and use it in GitHub Desktop.
Save mattpolzin/1b98a22642e46387f6b867fd4e5e37c8 to your computer and use it in GitHub Desktop.
A simple template to follow for client side JSONAPI/ReSwift
import Foundation
import Combine
import JSONAPI
import JSONAPIResourceCache
import JSONAPICombine
import ReSwift
import CombineReSwift
import CombineAPIRequest
// MARK: - Resources
enum DaySegment: String, Codable { case morning, afternoon, evening, night }
enum WidgetDescription: JSONAPI.ResourceObjectDescription {
static let jsonType: String = "widget"
struct Attributes: JSONAPI.Attributes {
let title: Attribute<String>
let color: Attribute<String> // hex starting with #
}
// ignore relationships for now:
typealias Relationships = NoRelationships
}
typealias Widget = JSONAPI.ResourceObject<WidgetDescription, NoMetadata, NoLinks, String>
// MARK: - Resource Documents
typealias ManyWidgets = JSONAPI.Document<ManyResourceBody<Widget>, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, BasicJSONAPIError<String>>
// MARK: - Clientside Cache
struct EntityCache: ResourceCache, Equatable {
var widgets: ResourceHash<Widget> = [:]
mutating func merge(_ other: EntityCache) {
widgets.merge(other.widgets, uniquingKeysWith: { $1 })
}
}
// Make resource Materializable
extension WidgetDescription: Materializable {
static var cachePath: WritableKeyPath<EntityCache, ResourceHash<Widget>> { \.widgets }
}
// MARK: - ReSwift Store
struct AppState: StateType, Equatable {
var entities: EntityCache = .init() {
didSet {
print("Now have \(entities.widgets.count) widgets.")
}
}
}
// Entity Updates from the server are just
// simple Actions
struct EntityUpdate: Action {
let entities: EntityCache
init(_ entities: EntityCache) {
self.entities = entities
}
}
let store = ReSwift.Store(
reducer: { action, state in
var state = state ?? AppState()
// only handles the entity update action
switch action {
case let update as EntityUpdate:
state.entities.merge(update.entities)
default:
break
}
return state
},
state: AppState()
)
// MARK: - API
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
// Make an API request and store entities in the cache.
try APIRequest(
.get,
host: URL(string: "https://website.com")!,
path: "/widgets",
responseType: ManyWidgets.self
)
.publisher(using: decoder)
.entities
.dispatch { EntityUpdate($0) }
//.print() // just prints debug info to the console
.subscribe(store)
RunLoop.current.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment