Я использую ReactiveCocoa в приложении, которое вызывает вызовы для удаленных веб-API. Но прежде чем что-либо может быть извлечено с данного хоста API, приложение должно предоставить учетные данные пользователя и получить токен API, который затем используется для подписи последующих запросов.
Я хочу отвлечь этот процесс аутентификации, чтобы он автоматически выполнялся всякий раз, когда я вызываю вызов API. Предположим, у меня есть клиентский класс API, который содержит учетные данные пользователя.
// getThing returns RACSignal yielding the data returned by GET /thing.
// if the apiClient instance doesn't already have a token, it must
// retrieve one before calling GET /thing
RAC(self.thing) = [apiClient getThing];
Как я могу использовать ReactiveCocoa, чтобы прозрачно вызывать первый (и только первый) запрос API для извлечения и, в качестве побочного эффекта, безопасно хранить маркер API перед любыми последующими запросами?
Также я хочу использовать combineLatest:
(или подобное) для запуска нескольких одновременных запросов и что они все неявно ожидают получения токена.
RAC(self.tupleOfThisAndThat) = [RACSignal combineLatest:@[ [apiClient getThis], [apiClient getThat]]];
Кроме того, если запрос на получение-токен уже находится в полете при вызове API, этот вызов API должен дождаться завершения запроса на получение-токен.
Мое частичное решение следует:
Основной шаблон будет состоять в том, чтобы использовать flattenMap:
для сопоставления сигнала, который дает токен сигналу, который, учитывая токен, выполняет требуемый запрос и дает результат вызова API.
Предполагая некоторые удобные расширения для NSURLRequest
:
- (RACSignal *)requestSignalWithURLRequest:(NSURLRequest *)urlRequest {
if ([urlRequest isSignedWithAToken])
return [self performURLRequest:urlRequest];
return [[self getToken] flattenMap:^ RACSignal * (id token) {
NSURLRequest *signedRequest = [urlRequest signedRequestWithToken:token];
assert([urlRequest isSignedWithAToken]);
return [self requestSignalWithURLRequest:signedRequest];
}
}
Теперь рассмотрим реализацию подписки -getToken
.
- В тривиальном случае, когда токен уже получен, подписка сразу же дает токен.
- Если токен не был восстановлен, подписка отменяет вызов API аутентификации, который возвращает токен.
- Если вызов API аутентификации находится в полете, безопасно добавлять другого наблюдателя, не вызывая повторения вызова API аутентификации по проводке.
Однако я не уверен, как это сделать. Кроме того, как и где безопасно хранить токен? Какой-то постоянный/повторяемый сигнал?