A Moya-inspired flexible network abstraction layer
Lynn
Lynn is a Moya-inspired flexible network abstraction layer. With the core and storage manager protocol, it can be based on any network packages and storage technology.
Default implementations of core using URLSession
and storage manager using UserDefaults
are provided.
Basic Usage
Installation
You can install it through SPM:
.package(url: "https://github.com/loyihsu/Lynn", branch: "main"),
TargetGroup
Network requests are grouped into a Moya-styled TargetGroup
. A normal implementation of would be using an enum
.
enum SomeTargetGroup {
case someCase(someParameter: Int, anotherParameter: Int)
case anotherCase(someMessage: String)
}
extension SomeTargetGroup: TargetGroup {
var baseURL: String {
// base URL goes here, ex. 'http://example.com'
}
var path: String {
// path goes here, ex. 'some/case'
}
var task: LynnTask {
// map your task into a LynnTask, for example:
switch self {
case let .someCase(someParameter, anotherParameter):
return LynnTask(
method: .get,
parameters: [
"someParameter": someParameter,
"anotherParameter": anotherParameter
]
)
case let .anotherCase(someMessage):
return LynnTask(
method: .post,
body: HTTPBody(
content: ["someMessage": someMessage],
mode: .json
)
)
}
}
var headers: [String: String]? {
// Provide any header if needed; otherwise, just return `nil`.
}
var storageKey: String {
// This is the storage key used if you are using the cache system. Ex. 'someCase'
}
var sampleData: Data? {
// Provide any sample data if you want to use the `.sample` response mode.
}
}
LynnHandler
A LynnHandler
takes a LynnCore
and a LynnStorageManager
(if caching is needed). You can either use the LynnURLSession
implementation of Core
, or make your own LynnCore
. Using LynnURLSession
:
import Lynn
import LynnURLSession
let networkHandler = LynnHandler()
If you want to use the cache system, provide a storage manager here:
import Lynn
import LynnURLSession
import LynnUserDefaultsStorageManager
let networkHandler = LynnHandler(
storageManager: UserDefaultsItemStroageManager()
)
To use any custom core or storage manager, implement the LynnCore
or LynnStorageManager
protocols and provide them to the initialiser.
import Lynn
let networkHandler = LynnHandler(
networkCore: MyLynnCore(),
storageManager: MyLynnStorageManager()
)
By default, the LynnHandler
would retry up to 3 time if the request fails, you can set this number in the initialiser, too:
let networkHandler = LynnHandler(
storageManager: UserDefaultsItemStroageManager(),
maxRetries: 5
)
You can also specify the response mode here, there are multiple response modes defined:
.normal
would request from the cache first if a storage manager is provided and if no valid cache is found, it will request from the url specified..alwaysLive
would skip the cache and request from the live server immediately..sample
would request from the cache first if a storage manager is provided and if no valid cache is found, it will return and save thesampleData
specified in theTargetGroup
into the cache.
Just specify any response mode from above by:
let networkHandler = LynnHandler(
storageManager: UserDefaultsItemStroageManager(),
responseMode: .sample
)
Sending Requests
There are four main APIs provided:
request
using callback style returning data
networkHandler.request(
targetGroup: YourTargetGroup.target(parameter: 1),
getValidUntil: { data in
// return your cache invalidation time here
},
callback: { data in
// do something with the data
},
onError: { error in
// do something with the error
}
)
request
using callback style returning model
networkHandler.request(
targetGroup: YourTargetGroup.target(parameter: 1),
model: YourDecodableModel.self,
keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy....,
getValidUntil: { model in
// return your can invalidation time here
},
callback: { model in
// Do something with the model
},
onError: { error in
// Do something with the error
}
)
request
using async/await style returning data (macOS 10.15+, iOS 13+)
Task {
do {
let data = try await networkHandler
.request(
targetGroup: YourTargetGroup.target(parameter: 1),
getValidUntil: { data in
// return your can invalidation time here
}
)
// Do something with the data
} catch {
// Do something with the error
}
}
request
using async/await style returning model (macOS 10.15+, iOS 13+)
Task {
do {
let model = try await networkHandler
.request(
targetGroup: YourTargetGroup.target(parameter: 1),
model: YourDecodableModel.self,
keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy....,
getValidUntil: { model in
// return your can invalidation time here
}
)
// Do something with the model
} catch {
// Do something with the error
}
}
Cache
To use the cache system, add you would need to provide:
- A storage manager instance
getValidUntil
when making a request request
A storage manager can implement either one of LynnItemStorageManager
or LynnListStorageManager
, depending on whether you want to store an item or a list of items. Implementations for either an item or a list using UserDefaults
are provided:
import LynnUserDefaultsStorageManager
let networkHandler = LynnHandler(
storageManager: UserDefaultsItemStorageManager()
)
import LynnUserDefaultsStorageManager
let networkHandler = LynnHandler(
storageManager: UserDefaultsListStorageManager()
)