Combine을 활용한 다양한 API 호출
enum API {
case fetchTodos
case fetchPosts
case fetchUsers
var url: URL {
switch self {
case .fetchTodos:
return URL(string: "https://jsonplaceholder.typicode.com/todos")!
case .fetchPosts:
return URL(string: "https://jsonplaceholder.typicode.com/posts")!
case .fetchUsers:
return URL(string: "https://jsonplaceholder.typicode.com/users")!
}
}
}
enum ApiService {
static func fetchTodos() -> AnyPublisher<[Todo], Error> {
return AF.request(API.fetchTodos.url)
.publishDecodable(type: [Todo].self)
.value()
.mapError { afError in
return afError as Error
}
.eraseToAnyPublisher()
}
static func fetchPosts(todosCount: Int = 0) -> AnyPublisher<[Post], Error> {
return AF.request(API.fetchPosts.url)
.publishDecodable(type: [Post].self)
.value()
.mapError { afError in
return afError as Error
}
.eraseToAnyPublisher()
}
static func fetchUsers() -> AnyPublisher<[User], Error> {
return AF.request(API.fetchUsers.url)
.publishDecodable(type: [User].self)
.value()
.mapError { afError in
return afError as Error
}
.eraseToAnyPublisher()
}
static func fetchTodosAndPostsAtSameTime() -> AnyPublisher<([Todo], [Post]), Error> {
let fetchedTodos = fetchTodos()
let fetchedPosts = fetchPosts()
return Publishers.CombineLatest(fetchedTodos, fetchedPosts)
.eraseToAnyPublisher()
}
static func fetchTodosAndThenPosts() -> AnyPublisher<[Post], Error> {
fetchTodos().flatMap { todos in
return fetchPosts(todosCount: todos.count).eraseToAnyPublisher()
}.eraseToAnyPublisher()
}
static func fetchTodosAndPostsConditionally() -> AnyPublisher<[Post], Error> {
return fetchTodos()
.map { $0.count }
.filter { $0 >= 200 }
.flatMap { todosCount in
return fetchPosts(todosCount: todosCount).eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
}
final class ApiViewModel {
private var subscriptions = Set<AnyCancellable>()
func fetchTodos() {
ApiService.fetchTodos()
.sink { completion in
switch completion {
case .failure(let error):
print("ApiViewModel_error: \(error.localizedDescription)")
case .finished:
print("finish")
}
} receiveValue: { todos in
print("todos.count: \(todos.count)")
}
.store(in: &subscriptions)
}
func fetchPosts() {
ApiService.fetchPosts()
.sink { completion in
switch completion {
case .failure(let error):
print("ApiViewModel_error: \(error.localizedDescription)")
case .finished:
print("finish")
}
} receiveValue: { posts in
print("posts.count: \(posts.count)")
}
.store(in: &subscriptions)
}
func fetchTodosAndPostsAtSameTime() {
ApiService.fetchTodosAndPostsAtSameTime()
.sink { completion in
switch completion {
case .failure(let error):
print("ApiViewModel_error: \(error.localizedDescription)")
case .finished:
print("finish")
}
} receiveValue: { todos, posts in
print("todos.count: \(todos.count), posts.count: \(posts.count)")
}
.store(in: &subscriptions)
}
func fetchTodosAndThenPost() {
ApiService.fetchTodosAndThenPosts()
.sink { completion in
switch completion {
case .failure(let error):
print("ApiViewModel_error: \(error.localizedDescription)")
case .finished:
print("finish")
}
} receiveValue: { posts in
print("posts.count: \(posts.count)")
}
.store(in: &subscriptions)
}
func fetchTodosAndPostsConditionally() {
ApiService.fetchTodosAndPostsConditionally()
.sink { completion in
switch completion {
case .failure(let error):
print("ApiViewModel_error: \(error.localizedDescription)")
case .finished:
print("finish")
}
} receiveValue: { posts in
print("posts.count: \(posts.count)")
}
.store(in: &subscriptions)
}
func fetchTodosAndApiCallConditionally() {
let shouldFetchPosts: AnyPublisher<Bool, Error> =
ApiService.fetchTodos().map { $0.count < 200 }
.eraseToAnyPublisher()
shouldFetchPosts
.filter { $0 == true }
.flatMap { _ in
return ApiService.fetchPosts()
}.sink { completion in
switch completion {
case .failure(let error):
print("ApiViewModel_error: \(error.localizedDescription)")
case .finished:
print("finish")
}
} receiveValue: { posts in
print("posts.count: \(posts.count)")
}
.store(in: &subscriptions)
shouldFetchPosts
.filter { $0 == false }
.flatMap { _ in
return ApiService.fetchUsers()
}.sink { completion in
switch completion {
case .failure(let error):
print("ApiViewModel_error: \(error.localizedDescription)")
case .finished:
print("finish")
}
} receiveValue: { users in
print("users.count: \(users.count)")
}
.store(in: &subscriptions)
}
}