Skip to content

Instantly share code, notes, and snippets.

@bocato
Created March 25, 2022 14:04
Show Gist options
  • Save bocato/6c3d62935d8ea3cddd1aff109ffa9d68 to your computer and use it in GitHub Desktop.
Save bocato/6c3d62935d8ea3cddd1aff109ffa9d68 to your computer and use it in GitHub Desktop.
import Combine
public struct SomeRepository {
// Well defined errors, when possible.
public enum Error: Swift.Error {
case invalidData
}
// Public API as closures.
public let getList: () -> AnyPublisher<[String], Error>
}
extension SomeRepository {
/// The implementation of the logic, with Initializer Based Dependency Injection.
/// This should be *internal*, unless there is a real need to make it public.
static func instantiate(
session: URLSession,
jsonDecoder: JSONDecoder
) -> Self {
.init(
getList: {
session
.dataTaskPublisher(for: .init(string: "www.myapi.com/list")!)
.map(\.data)
.decode(type: [String].self, decoder: jsonDecoder)
.mapError { _ in Error.invalidData }
.eraseToAnyPublisher()
}
)
}
/// The real dependency, with the default parameters.
/// This can be *public*.
public static let live: Self = .instantiate(
session: .shared,
jsonDecoder: .init()
)
}
/* --- Usage --- */
final class MyViewModel {
// MARK: - Dependencies
private let someRepository: SomeRepository
// MARK: - Properties
private var subscriptions: Set<AnyCancellable> = .init()
// MARK: - Initialization
init(someRepository: SomeRepository = .live) {
self.someRepository = someRepository
}
func doSomethingUsingTheRepository() {
someRepository
.getList()
.sink(
receiveCompletion: { completion in /* do your magic 🧙‍♀️ */ },
receiveValue: { response in /* do your magic 🧙‍♀️ */ }
)
.store(in: &subscriptions)
}
}
/* --- Testing --- */
#if DEBUG
extension SomeRepository {
static func stub(
getListResult: Result<[String], Error>
) -> Self {
.init(
getList: { getListResult.publisher.eraseToAnyPublisher() }
)
}
static let dummy: Self = .init(
getList: { Empty().eraseToAnyPublisher() }
)
static let someSpecificScenarioThatIUseAlot: Self = .init(
getList: {
Just([])
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
)
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment