Monarch ? – WIP
A resource based, protocol oriented networking library designed for pure-SwiftUI applications.
Features:
- Async/Await
- Resource Based
- Protocol Oriented
- Caching Support
- Preview Support
- Extensible
- All the buzzwords!
Description
Monarch is a network library designed to harness the SwiftUI View Hierarchy to simplify dependency injection. It’s called Monarch because it sits at the top of your hierarchy.
To use Monarch, you register one or multiple request providers at a very high level of your view hierarchy.
struct MonarchApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.registerProvider(NetworkClient())
}
}
}
Any views lower in the view hierarchy can read the requestProvider
environment value and use it to execute a request. Because requests contain a previewData
value, views can be easily previewed in the Preview Canvas.
struct ContentView: View {
@Environment(\.requestProvider) var provider
@State var user: User?
var body: some View {
Text(user?.name ?? "Loading...")
.task {
do {
user = try await provider.perform(CurrentUserRequest())
} catch {
print("Whoops")
}
}
}
}
Creating a Request
Requests
are one of the basic building blocks of Monarch. They describe a resource, and can be defined with as few as two values.
struct CurrentUserRequest: Request {
var path: String { "users/me" }
var previewData: User { .example }
}
The RequestProvider Protocol
RequestProvider
is the protocol that powers most of the other protocols and classes in the library; it defines a single function:
func perform<R: Request>(_ request: R) async throws -> R.ResponseType
Network providers use this function to fetch data from the network, while cache providers use it to read values from memory or the disk.
Chaining Providers
By specifying the domain
property of a Request
you can determine which provider should receive that request.
When multiple providers are registered, Monarch will attempt to call them in the order they were registered.
extension RequestDomain {
static let images = RequestDomain(rawValue: 1 << 0)
}
struct MonarchApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.registerProvider(ImageCache(), domain: .images)
.registerProvider(ImageClient(), domain: .images)
.registerProvider(NetworkClient(), domain: .any)
}
}
}
In this example, any requests in the images
domain will be received by the ImageCache
, if no cache value is found, ImageClient
will fetch the image. Any other requests will be sent directly to NetworkClient
.