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.
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.
Para quem procura, apollo-link-context
agora é uma coisa:
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!
Comentários muito úteis
Para quem procura,
apollo-link-context
agora é uma coisa:https://github.com/apollographql/apollo-link/blob/5fbaaf47e5ff1189d65ee674f09fbda464c23d5a/packages/apollo-link-context/README.md