Estratégia de cache da API REST para coleta de registros

5

Estou projetando uma API REST para meus clientes móveis interagirem com nosso servidor de aplicativos (criado com Django / django-rest-framework, se isso fizer alguma diferença).

Há vários objetos diferentes acessíveis através da API, alguns mudando frequentemente (digamos, diários), alguns quase nunca mudando (em média menos de uma vez por mês) e outros para os quais apenas alguns registros aninhados serão alterados (pense um post de blog para o qual adicionamos novos comentários algumas vezes por dia).

Como os clientes são sensíveis ao volume de transferência de dados (por motivos de custo, dados móveis em países em desenvolvimento), quero limitar isso, especialmente quando eles baixam uma lista de objetos (por exemplo: a lista de objetos de blog mencionados anteriormente) . A transferência de dados é de longe a minha maior preocupação aqui, muito antes da carga do lado do servidor.

Pensei em usar algo semelhante ao cabeçalho HTTP If-Modified-Since (seção link 14.25), que poderia funcionar em solicitações de objetos individuais, como GET /api/blogposts/<id>/ . Mas com alta latência de rede (tempos de ping de mais de 500 ms são comuns), executar dezenas ou centenas de solicitações parece ser uma má ideia.

Para obter uma coleção de registros, esperaria que o comportamento a seguir ajudasse mais no meu caso (as solicitações das quais estou falando são semelhantes às descritas em esta resposta : coleções taylored por usuário)

GET /api/myblogposts/ retornaria inicialmente uma lista de objetos JSON, não apenas os IDs:

[
'post1': {...},
'post2': {...},
...
'postN': {...}
]

Em seguida, um GET subsequente no mesmo URL com o cabeçalho If-Modified-Since: Sat, 29 Oct 2016 19:43:31 GMT apropriado filtraria a lista para retornar apenas os registros modificados desde então. O cliente pode, então, mesclar as alterações em seu armazenamento de dados local.

Essa estratégia parece fazer sentido? Existe algum padrão existente para o cliente e o servidor negociarem o subconjunto de registros a serem transferidos?

    
por Laurent S 17.02.2017 / 12:58
fonte

1 resposta

3

Se você realmente pensar sobre isso, se um registro não tiver sido alterado, ele já estará "em cache", porque o registro de data e hora updated_at não foi alterado; Assim, sua intuição sobre a busca apenas de registros que foram modificados é a melhor maneira de realizar esse "cache". No entanto, eu não chamaria isso de "cache", mas "recuperação seletiva".

No entanto, como @Joeri Sebrechts mencionou em seu comentário, usar cabeçalhos HTTP de uma maneira não padronizada é uma maneira muito boa de irritar os mantenedores do código enquanto eles lutam para descobrir por que você está usando If-Modified-Since como um parâmetro de consulta para filtrar registros. Na verdade, é exatamente por isso que ele sugeriu usar um parâmetro de consulta - eles são usados exatamente para essa finalidade - e concordo plenamente.

Portanto, a solução aqui é:

  1. Inicialmente, busque todos os registros necessários (por exemplo, na inicialização)
    • armazena esse valor no cliente como um registro de data e hora - changed-after (ou o nome que você quiser dar ao nome - ao fazer o GET
    • certifique-se de que o registro id esteja incluído, para que você possa criar uma fusão interessante com os registros existentes mais tarde
  2. Quando o cliente precisar recuperar novos registros ou atualizar a lista, basta enviar outro GET para, por exemplo, %código%
    • sua API só recuperará registros com /records?changed-after=THE_STORED_TIMESTAMP
    • envia esses registros de volta para o cliente
  3. No cliente, faça uma operação de mesclagem na sua lista existente de registros
    • não exclua registros da lista
    • basta pegar o conjunto de novos registros, localizá-los na lista antiga e substituí-los
    • deixe o restante da lista inalterado

Algumas outras aplicações usam websockets para comunicar alterações aos clientes; por exemplo. o servidor detecta uma alteração em um registro e envia a todos os clientes que uma atualização está disponível para recuperação. Isso seria, na minha opinião, a maneira mais "eficiente" de fazer as coisas no caso de você ter milhões e milhões de registros que levariam muito tempo para consultar, e você tem a largura de banda disponível para websockets. Em vez de ter clientes constantemente procurando atualizações que podem ou não estar disponíveis (e a possibilidade de essas consultas serem caras), basta você informar ao servidor quando precisar atualizá-lo.

No entanto, não sabemos nada sobre a quantidade e a complexidade de seus dados, mas o simples fato de você ter uma situação de alta latência e baixa largura de banda elimina a possibilidade de usar websockets, portanto, o parâmetro de consulta updated_at > changed-after filter parece ser a abordagem mais apropriada.

PS - Se você é realmente muito limitado em dados, você pode até mesmo implementar um changelog de seus registros para saber quais campos foram alterados , permitindo que você envie seletivamente apenas os campos que foram realmente atualizados, em vez do registro inteiro. Alguns frameworks / idiomas têm bibliotecas que fazem isso, por exemplo Trilha de papel do Rails, . Se você acha que a necessidade de uso de largura de banda muito baixa vale a pena adicionar essa dependência, eu recomendo strongmente. Às vezes, essas bibliotecas tornam isso ridiculamente fácil, como os métodos do Paper Trails para diferenciar as versões , que fornecem apenas os dados isso foi mudado. Assim, você poderia enviar apenas esse dat, junto com o registro update_at , e mesclar seletivamente o cliente em uma base em vez de uma base registro completo . Puro!

    
por 19.02.2017 / 17:04
fonte