Apollo-link: [apollo-link-offline] Qual é a sua ideia?

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

Olá, eu ficaria muito feliz em participar desta construção de recurso. Porque eu realmente preciso disso para o presente projeto. Mas preciso de algumas dicas para começar. Alguém tem alguma idéia?

enhancement

Comentários muito úteis

Ei pessoal, tentei montar uma implementação básica para react-native que tenha um comportamento semelhante ao apollo-offline .
(ping https://github.com/Malpaux/apollo-offline/issues/14)

Você pode verificar nesta essência: https://gist.github.com/lachenmayer/2e364a5ca9ae0918eb032867d0c6720d

É uma combinação de:

Quando o dispositivo ficar off-line, as solicitações serão colocadas na fila e serão retiradas quando ele ficar on-line novamente. ( apollo-link-queue )

Qualquer solicitação que falhe com um erro de rede será repetida (atualmente, infinitamente). ( apollo-link-retry )
Observe que isso pode ser porque o dispositivo está offline ou o back-end simplesmente não pode ser alcançado (por exemplo, se estiver inativo).

No entanto, se pudermos resolver a consulta do cache, ela não será tentada novamente e, em vez disso, os dados no cache serão usados ​​como a resposta. Isso é implementado na função optimisticFetchLink .

Na minha opinião, esse comportamento de "busca otimista" é uma das partes mais importantes do apollo-offline, e qualquer implementação futura de apollo-link-offline deve suportar isso. Isso permite que o usuário continue usando o aplicativo normalmente enquanto está offline, desde que os dados tenham sido buscados e persistidos em algum ponto. Na minha opinião, este deve ser o comportamento padrão da política de busca network-and-cache , mas infelizmente não parece que isso vai mudar tão cedo (consulte https://github.com/apollographql/react-apollo/issues/ 604 # issuecomment-355648596).

Se você salvar a essência como offlineLink.js , poderá usá-la da seguinte maneira:

import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'

// get this from https://gist.github.com/lachenmayer/2e364a5ca9ae0918eb032867d0c6720d
import { createOfflineLink } from './offlineLink'

const cache = new InMemoryCache()
const networkLink = createHttpLink()

const offlineLink = createOfflineLink({ cache })

const link = ApolloLink.from([
  // ... + other links ...
  offlineLink,
  networkLink,
])

const client = new ApolloClient({
  cache,
  link,
}

Problemas conhecidos / bits ausentes

  • Isso só funciona com o reagente nativo por enquanto. A verificação isOnline deve ser abstraída para fazer esta plataforma cruzada.
  • Se você tiver apenas uma resposta parcial no cache, receberá uma promessa rejeitada em algum ponto da linha, informando que a resposta está incompleta. Eu ainda não descobri como consertar isso, ou mesmo como o Apollo-offline resolve isso. Se você quiser tentar consertar isso, gostaria de receber qualquer indicação sobre isso.
  • No momento, você não pode alterar nenhuma das configurações de nova tentativa - isso deve ser adicionado como um parâmetro de configuração extra.
  • Você não tem controle sobre a busca otimista. Você deve ser capaz de definir isso independentemente para cada consulta. Não sou um grande fã da implementação apollo-offline disso (definindo uma variável de consulta {__online_: true} ), mas definitivamente deve haver uma maneira de fazer isso.
  • Obviamente, também não há testes.

Agradeço a quem está procurando uma solução para tentar fazer isso, e podemos então transformar isso em um módulo npm adequado com digitações, testes, documentos e todo o lote. Este comportamento é super importante na minha opinião, e é uma pena que apollo-client 2 não tenha uma solução adequada para isso ainda.

Legal ✌️

Todos 38 comentários

O que você consideraria como o caso de uso típico?

Como um aplicativo offline:

  • Todas as solicitações do graphql são adicionadas à fila. (pode ser armazenado no cache).
  • Quando o aplicativo recebe o sinal online, ele informa o link para reenviar a solicitação anterior.

Eu imagino que seja usado assim:

import { NetInfo } from 'react-native';
import OfflineLink from 'apollo-link-offline';

const offlineLink = new OfflineLink({
  isOnlineAsync: () => NetInfo.isConnected.fetch(),
});

NetInfo.isConnected.addEventListener('change', (isConnected) => {
  if (isConnected) {
    offlineLink.resubmit();
  }
});

Acho que essa seria uma funcionalidade incrível. A forma como vejo isso potencialmente acontecendo, seria fazer com que o Apollo-link-offline definisse um conjunto de consultas e mutações que precisam ser usadas offline.

Uma vez que eles são definidos, no fundo do aplicativo, podemos buscar todos os dados das Consultas e armazená-los no armazenamento local. Para as Mutações, precisaríamos de todos os campos criados no armazenamento local para que possamos armazenar todos os dados criados offline.

Dessa forma, ainda podemos executar a funcionalidade offline enquanto armazenamos os dados em um cache local.
Também passaríamos nos testes de PWA do Google se pudéssemos nos vincular a Service Workers
Então, quando o aplicativo ficar online novamente, todas as mutações que ocorreram no cache local podem ser passadas de volta para a API.

Obviamente, é necessário haver alguma forma de proteção de simultaneidade em vigor.

Minha preocupação é que o usuário A (offline) atualizou a Tabela X, enquanto o usuário B (online) atualizou a Tabela X enquanto o usuário A estava offline. Precisaríamos de alguma forma de regras de simultaneidade aqui. Eu acho que pode ser orientado por data, mas não resolve o problema se o usuário A substituir os dados do usuário B sem que o usuário B esteja ciente.

Ou podemos simplesmente falhar na mutação e deixar o usuário atualizar manualmente quando estiver online novamente.

Apollo Client 2 é incrível, mas esta parte da funcionalidade seria uma besteira absoluta de cães

Eu também seria um grande fã disso. Eu sei que tem havido várias tentativas de lidar com isso com a loja Redux do 1.0, mas torná-lo um cidadão pleno do ecossistema Apollo 2.0 com uma abordagem consistente seria maravilhoso.

A maior parte do que foi abordado aqui já faz muito sentido para mim - basicamente, quero persistir meus dados no armazenamento local e, em seguida, puxá-los de lá para o Apollo após o fato. Secundariamente, enfileirando as mutações.

Como uma espécie de meta terciária, ser capaz de sugar ainda mais dados em segundo plano também seria ótimo, e algo que tentarei fazer de qualquer maneira. Na verdade, gostaria de armazenar quase todos os dados do usuário localmente também, apenas para tornar as operações de consulta comuns muito mais rápidas e, em seguida, reidratar para obter precisão total, permitindo a rede. Portanto, algum tipo de solução para esse ângulo ansioso de carregar para mais tarde seria ótimo, especialmente porque os Service Workers estão começando a se tornar viáveis ​​com o Safari finalmente tendo-os em uma prévia da tecnologia.

Eu também estou animado com isso. @danieljvdm Começou um pouco com a persistência em um problema no repositório do cliente apollo .

Acho que o RetryLink será útil para gerenciar erros de rede e novas tentativas, embora eu gostaria de ver algum tipo de queda como ocorreu com o redux-offline .

Isso é bem legal. O problema que @ 2WheelCoder referenciou é uma abordagem inicial e talvez ingênua voltada mais para a persistência do cache em vez de suporte offline completo (consultas / mutações de enfileiramento e outros).

Ainda pode ser um lugar decente para começar e construir em cima. O que indiquei nesse problema é que atualmente não tenho uma boa maneira de monitorar o cache em busca de alterações. Na verdade, tentei implementar a sugestão inicial de @ 2WheelCoder hoje cedo, mas encontrei problemas semelhantes. O problema com a criação de um ApolloLink para "monitorar mudanças na loja" é que ele vive apenas no contexto entre uma ação do cliente e a gravação subsequente do cache. Portanto, posso interceptar a solicitação antes de sair (middleware) e interceptá-la antes de ser gravada no cache (afterware), mas não sei quando ela _foi_ gravada - só posso adivinhar (meu hack atual é um tempo limite de 1000ms )

Outra falha fatal com o uso de um link para persistência offline é que ele não leva em conta as assinaturas. Um link de assinatura só será disparado quando a assinatura for aberta, não em eventos subsequentes (talvez haja uma maneira de fazer isso que eu esqueci?).

É basicamente onde estou agora, e estou muito preso - acho que para ir mais longe talvez tenha que abrir um PR para apollo-cache-inmemory.

@danieljvdm Estou no mesmo lugar e acho que faz sentido lidar com a persistência diretamente no cache depois de encontrar o mesmo problema que você. O HttpLink simplesmente não é adequado para isso, pois o observável é concluído após a solicitação, mas (normalmente) antes das atualizações do cache.

Embora possa valer a pena abrir um PR em apollo-cache-inmemory, também me pergunto se seria melhor bifurcá-lo em um novo projeto. A modularidade da Apollo 2 em torno do cache e do link parece sugerir que, se você precisar de um tipo diferente de cache, pode simplesmente criá-lo. Talvez um problema no apollo-client seja a próxima etapa (não acho que apollo-cache-inmemory tenha seu próprio repo)?

Pedimos desculpas por sair um pouco do assunto dos links aqui.

@holman , você teria uma referência sobre o trabalhador de serviço na prévia da tecnologia do safari?

@sedubois caiu (meio de repente) um mês ou dois atrás. Está em uma prévia da tecnologia , mas ainda

@ 2WheelCoder Eu gosto da ideia de um PR para o cliente Apollo para um novo cache. Talvez apollo-offline-cache que pode estender apollo-cache-inmemory ? Eu estaria disposto a ajudar a trabalhar nisso. Quer abrir um problema aí?

@ 2WheelCoder @danieljvdm que tal usar LocalForage para a persistência https://github.com/localForage/localForage Se vocês abrirem um PR, estaria disposto a ajudar

@danieljvdm Sim, vou abrir um exemplar se você quiser fazer uma RP. Não terei muito tempo na próxima semana e meia, mas estou feliz em começar depois disso.

@Eishpirate Concordo com certeza que LocalForage é ótimo. Acho que a forma como o redux-persist conseguiu salvar a loja foi bastante sólida e provavelmente pode atuar como um padrão decente a ser seguido em apollo-offline-cache .

Pessoal, estou usando o pacote de persistência redux para salvar os dados da loja no AsyncStorage nativo do react. Como faço isso agora? Qualquer ideia?

@Eishpirate : o localforage funciona para reagir nativo? Olhando o gráfico de compatibilidade da biblioteca, não consigo encontrar nada sobre react native. https://github.com/localForage/localForage/wiki/Supported-Browsers-Platforms

Seria muito triste se o recurso off-line do Apollo não funcionasse para aplicativos.

@timLoewel é um ponto muito bom. Não tinha realmente pensado tão à frente quanto React Native. Não acredite que explicitamente o faça.

Isso pode causar problemas inesperados mais adiante. Não tenho certeza, porém, se há uma alternativa viável sem ter que reinventar a roda

Artigo interessante que pode ser relevante para esta discussão https://blog.logrocket.com/building-an-offline-first-app-with-react-and-rxdb-e97a1fa64356?t=now

Parece muito promissor usar rxdb como banco de dados offline. Isso é compatível com as opções React, React-Native, Vue, Angular, praticamente as mais populares.

O problema que encontro, porém, é que ele precisa sincronizar com um banco de dados noSQL como o PouchDB (derivado do CouchDB). No meu caso de uso, estou usando um banco de dados SQL relacional (Postgres) e toda a minha validação de dados ocorre no nível do banco de dados. Se eu tivesse que usar esse sistema, precisaria manter a validação por meio do jsonschema.

Não segue os princípios DRY e, definitivamente, apresentaria problemas.

Outra opção que encontrei é Kinto http://docs.kinto-storage.org/en/stable/index.html que funciona com Postgres, portanto, deve evitar algumas das camadas extras de complexidade que o rxdb introduziria. Kinto usa HTTP, então podemos teoricamente apenas conectá-lo ao Apollo-link-http https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-http

Parece que muito do trabalho estará relacionado ao armazenamento em cache.

Que tal redux? (Estou falando sério)

Um pacote apollo-link-offline , baseado no trabalho apollo-offline e ...
Um pacote apollo-cache-redux . Use redux-offline / redux-persist assim como apollo-offline faz agora.

A Apollo criou o cache de memória como a solução genérica padrão - posso entender por que eles não queriam ser vinculados tão intimamente a outra biblioteca. Mas a solução redux / redux-offline / redux-persis é tão testada na batalha ... ainda é uma ótima escolha. O desenvolvimento é muito ativo para todos os três.

EDIT: apollo-cache-redux existe agora, graças a @rportugal

@giautm Implementei exatamente o que você descreveu para um pequeno projeto meu há pouco e decidi publicá-lo como um pacote realmente simples: apollo-link-queue . Se algum de vocês tiver ideias para melhorias, eu adoraria receber suas sugestões ou contribuições.

Qual é o estado deste problema? Existe algo que podemos usar para coisas offline que seja da Apollo e não relacionado ao Redux Offline?

@smithaitufe ,
Sim, você pode usar apollo-cache-persist .

@ Gregor1971
Obrigado por esta referência. Vou experimentar e apresentar minhas observações.
Em uma aparência superficial, parece legal e fácil de implementar.

Como isso difere de apollo-link-queue

Ei pessoal, tentei montar uma implementação básica para react-native que tenha um comportamento semelhante ao apollo-offline .
(ping https://github.com/Malpaux/apollo-offline/issues/14)

Você pode verificar nesta essência: https://gist.github.com/lachenmayer/2e364a5ca9ae0918eb032867d0c6720d

É uma combinação de:

Quando o dispositivo ficar off-line, as solicitações serão colocadas na fila e serão retiradas quando ele ficar on-line novamente. ( apollo-link-queue )

Qualquer solicitação que falhe com um erro de rede será repetida (atualmente, infinitamente). ( apollo-link-retry )
Observe que isso pode ser porque o dispositivo está offline ou o back-end simplesmente não pode ser alcançado (por exemplo, se estiver inativo).

No entanto, se pudermos resolver a consulta do cache, ela não será tentada novamente e, em vez disso, os dados no cache serão usados ​​como a resposta. Isso é implementado na função optimisticFetchLink .

Na minha opinião, esse comportamento de "busca otimista" é uma das partes mais importantes do apollo-offline, e qualquer implementação futura de apollo-link-offline deve suportar isso. Isso permite que o usuário continue usando o aplicativo normalmente enquanto está offline, desde que os dados tenham sido buscados e persistidos em algum ponto. Na minha opinião, este deve ser o comportamento padrão da política de busca network-and-cache , mas infelizmente não parece que isso vai mudar tão cedo (consulte https://github.com/apollographql/react-apollo/issues/ 604 # issuecomment-355648596).

Se você salvar a essência como offlineLink.js , poderá usá-la da seguinte maneira:

import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'

// get this from https://gist.github.com/lachenmayer/2e364a5ca9ae0918eb032867d0c6720d
import { createOfflineLink } from './offlineLink'

const cache = new InMemoryCache()
const networkLink = createHttpLink()

const offlineLink = createOfflineLink({ cache })

const link = ApolloLink.from([
  // ... + other links ...
  offlineLink,
  networkLink,
])

const client = new ApolloClient({
  cache,
  link,
}

Problemas conhecidos / bits ausentes

  • Isso só funciona com o reagente nativo por enquanto. A verificação isOnline deve ser abstraída para fazer esta plataforma cruzada.
  • Se você tiver apenas uma resposta parcial no cache, receberá uma promessa rejeitada em algum ponto da linha, informando que a resposta está incompleta. Eu ainda não descobri como consertar isso, ou mesmo como o Apollo-offline resolve isso. Se você quiser tentar consertar isso, gostaria de receber qualquer indicação sobre isso.
  • No momento, você não pode alterar nenhuma das configurações de nova tentativa - isso deve ser adicionado como um parâmetro de configuração extra.
  • Você não tem controle sobre a busca otimista. Você deve ser capaz de definir isso independentemente para cada consulta. Não sou um grande fã da implementação apollo-offline disso (definindo uma variável de consulta {__online_: true} ), mas definitivamente deve haver uma maneira de fazer isso.
  • Obviamente, também não há testes.

Agradeço a quem está procurando uma solução para tentar fazer isso, e podemos então transformar isso em um módulo npm adequado com digitações, testes, documentos e todo o lote. Este comportamento é super importante na minha opinião, e é uma pena que apollo-client 2 não tenha uma solução adequada para isso ainda.

Legal ✌️

@smithaitufe ,

Como isso difere de apollo-link-queue?

Parece que o apollo-link-queue faz coisas inteligentes com base no status da conexão. apollo-cache-persist salva o cache; permitindo, por exemplo, que os usuários iniciem e executem seu aplicativo enquanto estiverem desconectados. Sem persistir o cache, seu aplicativo precisaria de conectividade para iniciar,

Provavelmente desejaremos ambas, ou melhor ainda, a solução de @lachenmayer acima (que usa apollo-link-queue) e um cache que seja persistente. (estamos batendo papo nos repositórios de links, portanto, o foco aqui está mais voltado para isso)

@lachenmayer À primeira vista, sua abordagem parece muito atraente.

Eu concordo totalmente com você sobre a necessidade de algo como o recurso de busca otimista de apollo-offline . Isso (ou melhor, a falta dele) foi em grande parte o que me inspirou a começar apollo-offline .

Eu mesmo não estou muito satisfeito com a maneira como tive que implementar a ativação / desativação seletiva do recurso de busca otimista em apollo-offline . As variáveis ​​de consulta não eram a primeira escolha, mas pareciam ser as mais práticas. O que você propõe?

As próximas semanas serão muito estressantes para mim. Depois disso, porém, ficaria mais do que feliz em contribuir para a implementação de uma primeira solução off-line atualizada para Apollo - pode ser uma nova versão do pacote apollo-offline ou algo como apollo-link-offline .

Obrigado @MLPXBrachmann!
Acho que a busca otimista deve ser controlada usando fetchPolicy - se não quiser que nada saia do cache, devo poder usar network-only .

@lachenmayer @MLPXBrachmann

Estou mais do que pronto e disposto a contribuir.

Eu também estou procurando opções para implementar o comportamento offline em um aplicativo Apollo. A abordagem de @lachenmayer parece super promissora, mas como ela depende de apollo-link-retry, as mutações que não foram aplicadas com sucesso não serão persistidas, portanto, se a página for atualizada, quaisquer dados que não tenham sido confirmados para o servidor serão descartado (suponho que seja a mesma coisa no react-native se o aplicativo for suspenso). Há algum trabalho ou pelo menos discussão sobre esse aspecto?

@nicocrm entendo ... No momento, a discussão em torno do suporte off-line está principalmente nesta questão. Acho que o próprio Apollo tem outras prioridades agora, então devemos criar um projeto comunitário apollo-link-offline . Esperamos que isso leve a mais discussão e progresso do que agora 😄

@benseitz Definitivamente sou a favor disso. Há muito interesse no recurso, então tenho certeza de que há espaço para um projeto comunitário - contanto que eu não esteja duplicando ou fragmentando o esforço existente, posso criar uma nova equipe e repo para apollo-link-offline e convidar todos os interessados . Tenho algum interesse pessoal, bem como um cliente que está realmente querendo esse recurso, então terei algumas horas para queimar nele. Vou perguntar no repositório apollo-offline para ver se eles querem assumir a liderança, já que têm muito mais experiência.

Eu definitivamente tenho interesse pessoal nisso também - ficaria feliz em conversar mais com você sobre este @nicocrm. Eu não notei nenhuma solicitação perdida até agora no react-native, mas tbh eu realmente não testei todas essas coisas corretamente (apenas com as consultas até agora e _parece_ executar tudo bem).

Acho que faria sentido iniciar um repo para isso. @MLPXBrachmann que construiu apollo-offline mencionado acima que não terá tempo para gastar melhorando apollo-offline nas próximas semanas, e acredito que faz mais sentido chamá-lo de apollo-link-offline .

Não acho que haja nenhum código reutilizável de apollo-offline , pois é muito específico para redux.

@nicocrm eu concordo muito com você. Consultas / mutações em fila persistentes definitivamente devem ser algo que um potencial apollo-link-offline cuida.

@benseitz Eu também acho que seria uma ótima ideia começar apollo-link-offline como um esforço da comunidade e gostaria muito de participar de seu desenvolvimento.

@lachenmayer Você está absolutamente certo, a quantidade de código compartilhada por apollo-offline e o pacote apollo-link-offline planejado provavelmente será quase nula. No entanto, acho que muitos dos conceitos básicos do primeiro ainda se aplicam ao desenvolver um kit de ferramentas offline definido no universo Apollo 2.0.

Em qualquer caso, ficaria feliz em discutir ideias para apollo-link-offline , dar feedback sobre a implementação e - assim que minha agenda ficar livre - contribuir com algum código também.

@MLPXBrachmann @lachenmayer @nicocrm Essa parece ser a maneira certa de fazer isso!
Já que qualquer pessoa pode abrir um canal público no Apollo Slack . Eu sugeriria abrir um chamado apollo-link-offline . Talvez isso torne a comunicação entre nós um pouco mais fácil. Todas as decisões importantes ainda devem ser documentadas nos problemas do GitHub.

Aceito abrir o canal repo e o slack channel ou um de vocês quer fazer isso?

Com certeza, obrigado!

Eu adicionei vocês três como colaboradores do Repo . E você pode entrar no canal #apollo-link-offline no Apollo Slack

Claro, todos estão convidados a colaborar no GitHub Repo e discutir no Slack :)
Estou muito animado 💯

Para aqueles que chegam aqui a partir de uma Pesquisa Google, escrevi um resumo de todas as tecnologias off-line existentes disponíveis hoje para o Apollo Client 2.0.

https://github.com/benseitz/apollo-link-offline/issues/1#issuecomment -371678922

O Apollo está trabalhando em um AWS AppSync equivalente? Já temos um servidor GraphQL e precisamos de cache de cliente offline para consultas e mutações usando nosso servidor, não soluções AWS (ou seja, Lamda, DynamoDB, Elastic Search).

espero que funcione.

@masull Isso seria absolutamente incrível. Eu tentei e não achei que o firebase ou a plataforma de análise funcionassem para mim, então ter esse recurso seria glorioso.
Tendo dificuldade em configurar tudo com muitos pacotes ... nada divertido :)

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