Apollo-link: Как обрабатывать асинхронные запросы?

Созданный на 9 окт. 2017  ·  3Комментарии  ·  Источник: apollographql/apollo-link

Привет, ребята, с нетерпением жду предстоящего выпуска Apollo Client 2.0! Я пытаюсь перейти на бета-версию, и у меня возникли трудности с настройкой моего промежуточного программного обеспечения для аутентификации. Мой токен авторизации хранится в моем приложении RN через AsyncStorage, который (как вы уже догадались) является асинхронным. Раньше это не было проблемой, так как это был промежуточный код, который я использовал для внедрения токена аутентификации в заголовок:

const authMiddleware = {
    async applyMiddleware(req, next) {
        if (!req.options.headers)
            // Create the header object if needed.
            req.options.headers = {};

        // Inject the auth header if it exists
        const authExists = await Storage.authToken.exists();

        if (authExists) {
            const token = await Storage.authToken.get();
            req.options.headers['Authorization'] = `Bearer ${token}`;
        }

        next();
    }
};

Теперь я переключился на новую реализацию Link, как описано здесь :

const authLink = new ApolloLink(async (operation, forward) => {
    const authExists = await Storage.authToken.exists();

    if (authExists) {
        const token = await Storage.authToken.get();

        operation.setContext({
            headers: {
                Authorization: `Bearer ${token}`
            }
        });
    }

    return forward(operation);
});

Единственная проблема заключается в том, что новой библиотеке не нравится ключевое слово async . Когда я удаляю его и комментирую все, кроме оператора return, я получаю (как и следовало ожидать) ошибку 403 с моего сервера. Однако с добавлением ключевого слова я получаю:

Network error: undefined is not a function (near '..._this.inFlightRequestObservables[key].subscribe...')

Я предполагаю, что это связано с тем фактом, что объект запроса возвращает обещание вместо ожидаемого значения. Есть ли какой-нибудь подход, который мог бы исправить это?

Предполагаемый результат:

Приложение должно применять промежуточное ПО, несмотря на использование промисов.

Фактический результат:

Вышеупомянутая ошибка возникает, если присутствует ключевое слово async ... даже без него... вам все равно нужно вернуть вызов forward() внутри метода then() , который не работает.

Как воспроизвести проблему:

Я считаю, что добавление async к функции запроса любого вызова конструктора ApolloLink сделает это.

Самый полезный комментарий

Все 3 Комментарий

Итак, приложив достаточно усилий, я смог сам придумать исправление:

const authLink = new ApolloLink((operation, forward) => {
    return new Observable(observable => {
        let sub = null;

        Storage.authToken.exists().then(exists => {
            if (exists) {
                Storage.authToken.get().then(token => {
                    operation.setContext({
                        headers: {
                            Authorization: `Bearer ${token}`
                        }
                    });

                    sub = forward(operation).subscribe(observable);
                });
            } else {
                sub = forward(operation).subscribe(observable);
            }
        });

        return () => (sub ? sub.unsubscribe() : null);
    });
});

Тем не менее, я очень новичок в этой библиотеке, поэтому я надеюсь, что моя реализация не откроет двери для каких-либо уязвимостей. Я думаю, что, поскольку sub ссылаются, а не копируют, значение null будет преобразовано в правильную подписку после разрешения промиса. В любом случае, пока закрываю. Надеюсь, этот код кому-то поможет.

Однако я получил ту же ошибку без async на constructor , но async на Observable constructor . Вы можете воспроизвести его следующим образом:

new ApolloLink(() => {
  return new Observable(async observer => {
    await new Promise((resolve, reject) => setTimeout(resolve, 1000))

    observer.next({data: {}})
    observer.complete()
  })
})

Или самый минимальный шаг для репликации:

new ApolloLink(() => {
  return new Observable(() => {
    return new Promise()
  })
})

Очень странно, как если бы я разворачивал async / await следующим образом:

new ApolloLink(() => {
  return new Observable(observer => {
    const timeoutPromise = new Promise((resolve, reject) => setTimeout(resolve, 1000))

    timeoutPromise.then(() => {
      observer.next({data: {}})
      observer.complete()
    })
  })
})

Тогда все хорошо.

Кажется, что библиотека Observable не любит AsyncFunction s (которые по сути такие же, как возвращенные Promise )? Я бы не догадался об этом, поскольку не должно иметь значения, что возвращает constructor , если observer.{next/complete/error/etc} вызывается в пределах constructor соответственно.

Дайте мне знать, если вам потребуется дополнительная информация. Рад открыть отдельную тему, чтобы отслеживать и это.

Спасибо!

Была ли эта страница полезной?
0 / 5 - 0 рейтинги