У меня есть ContentService
, который делает запрос на статью. Этот ответ на статью содержит свойство authorId
.
У меня есть ProfileService
, который позволяет мне запросить профиль пользователя по userId
.
Я пытаюсь запросить статью из цепочки ContentService
по запросу один разкоторый завершается до ProfileService
с использованием свойства authorId
, тогда я хотел бы вернуть ContentArticleViewModel
, который содержит как статью, так и информацию профиля.
Мой ArticleInteractor
выглядит примерно так -
final class ArticleInteractor: ArticleInteractorInputProtocol {
let fetchArticleTrigger = PublishSubject<String>()
private lazy var disposeBag = DisposeBag()
weak var output: ArticleInteractorOutputProtocol? {
didSet {
configureSubscriptions()
}
}
private func configureSubscriptions() {
guard let output = output else { return }
fetchArticleTrigger
.bind(to: dependencies.contentSvc.fetchContentByIdTrigger)
.disposed(by: disposeBag)
dependencies.contentSvc.fetchContentByIdResponse
.bind(to: output.fetchArticleResponse)
.disposed(by: disposeBag)
}
}
Очень просто fetchArticleTrigger
запускает запрос, затем я bind
на dependencies.contentSvc.fetchContentByIdResponse
и принимаю ответ.
Метод на моем ContentService
-
// MARK:- FetchContentById
// @params: id - String
// return: PublishSubject<ContentArticle>
fetchContentByIdTrigger
.flatMapLatest { [unowned self] in self.client.request(.getContentById(id: $0)) }
.map { (resp: Result<ContentArticle>) in
guard case .success(let props) = resp else { return ContentArticle() }
return props
}
.bind(to: fetchContentByIdResponse)
.disposed(by: disposeBag)
У меня есть очень похожая настройка на моем ProfileService
-
// MARK:- FetchUserProfileById
// @params: id - String
// return: PublishSubject<User>
fetchUserProfileByIdTrigger
.flatMapLatest { [unowned self] in self.client.request(.getProfileByUserId(id: $0)) }
.map { (resp: Result<User>) in
guard case .success(let props) = resp else { return User() }
return props
}
.bind(to: fetchUserProfileByIdResponse)
.disposed(by: disposeBag)
Я думаю, я создам модель для статьи, что-то вроде -
struct ContentArticleViewModel {
var post: ContentArticle
var user: User
}
IЯ представлял себе что-то вроде этого псевдокода в моем ArticleInteractor
-
dependencies.contentSvc.fetchContentByIdResponse
.flatMapLatest { article in
/* fetch profile using `article.authorId */
}.map { article, profile in
return ContentArticleViewModel(post: article, user: profile)
}
.bind(to: output.fetchArticleResponse)
.disposed(by: disposeBag)
Но я совершенно растерялся, как лучше всего справиться с этим. Я видел несколько статей о цепочечных запросах, но изо всех сил пытаюсь что-нибудь успешно применить.
РЕДАКТИРОВАТЬ
У меня сейчас что-то работает -
private func configureSubscriptions() {
guard let output = output else { return }
fetchArticleTrigger
.bind(to: dependencies.contentSvc.fetchContentByIdTrigger)
.disposed(by: disposeBag)
dependencies.contentSvc.fetchContentByIdResponse
.do(onNext: { [unowned self] article in self.dependencies.profileSvc.fetchUserProfileByIdTrigger.onNext(article.creator.userId)})
.bind(to: fetchArticleResponse)
.disposed(by: disposeBag)
let resp = Observable.combineLatest(fetchArticleResponse, dependencies.profileSvc.fetchUserProfileByIdResponse)
resp
.map { [unowned self] in self.enrichArticleAuthorProps(article: $0, user: $1) }
.bind(to: output.fetchArticleResponse)
.disposed(by: disposeBag)
}
private func enrichArticleAuthorProps(article: ContentArticle, user: User) -> ContentArticle {
var updatedArticle = article
updatedArticle.creator = user
return updatedArticle
}
Однако я не уверен, что это правильно.