Apollo-link: Como lidar com solicitações assíncronas?

Criado em 9 out. 2017  ·  3Comentários  ·  Fonte: apollographql/apollo-link

Oi pessoal, animado para o lançamento do Apollo Client 2.0! Estou tentando migrar para a versão beta e estou tendo dificuldade em configurar meu middleware de autenticação. Meu token de autenticação é armazenado no meu aplicativo RN via AsyncStorage, que (você adivinhou), é assíncrono. Anteriormente, isso não era um problema, pois este era o código de middleware que eu estava usando para injetar o token de autenticação no cabeçalho:

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();
    }
};

Agora mudei para a nova implementação do Link, conforme documentado aqui :

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);
});

O único problema parece ser que a nova biblioteca não parece gostar da palavra-chave async . Quando eu removo e comento tudo, exceto a instrução de retorno, recebo (como seria de esperar) um erro 403 do meu servidor. No entanto, com a palavra-chave adicionada, recebo:

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

Imagino que isso tenha a ver com o fato de o objeto de solicitação estar retornando uma promessa em vez de seu valor esperado. Existe alguma abordagem que possa remediar isso?

Resultado pretendido:

O aplicativo deve aplicar middleware apesar do uso de promessas.

Resultado real:

O erro acima é gerado se a palavra-chave async estiver presente.. mesmo sem ela, você ainda precisa retornar a chamada forward() dentro de um método then() , o que seria não funciona.

Como reproduzir o problema:

Acredito que adicionar async à função de solicitação de qualquer chamada do construtor ApolloLink faria isso.

Comentários muito úteis

Todos 3 comentários

Então, com ajustes suficientes, consegui realmente encontrar uma correção:

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);
    });
});

Dito isso, sou muito novo nessa biblioteca, então espero que minha implementação não abra a porta para nenhuma vulnerabilidade. Eu acho que porque sub está apenas sendo referenciado e não copiado, o null será resolvido para a assinatura apropriada assim que a Promise for resolvida. Enfim, fechando por enquanto. Espero que este código ajude alguém.

Eu recebi o mesmo erro, no entanto, sem async no constructor , mas async no Observable constructor . Você pode replicá-lo da seguinte forma:

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

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

Ou o passo mais mínimo para replicar:

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

É muito estranho como se eu desenrolasse o async / await da seguinte forma:

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

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

Então está tudo bem.

Parece que a biblioteca Observable não gosta AsyncFunction s (que são essencialmente os mesmos que um Promise retornado)? Eu não teria adivinhado isso, pois não deveria importar o que os constructor retornam, desde que observer.{next/complete/error/etc} sejam chamados dentro do constructor acordo.

Deixe-me saber se você precisar de alguma informação adicional. Feliz em abrir uma edição separada para acompanhar isso também.

Obrigado!

Esta página foi útil?
0 / 5 - 0 avaliações