Resto design - Várias chamadas vs retornando todos os dados em uma chamada

8

Estou tentando criar uma API de descanso para um aplicativo Android. Suponha que eu tenha uma userstabela com (id, name, email)e uma songstabela com (id, song_name, album)e uma associação de junção rica entre eles como streamstendo (user_id, song_id, listen_count). Quero buscar detalhes sobre todos os fluxos e mostrá-lo no aplicativo como uma lista. A lista mostraria o nome da música, o nome do álbum, o nome do usuário e a contagem de escutas. Eu vejo três opções plausíveis -

  1. GETpara /streamse buscar uma lista de todos os song_idse user_ids. Em seguida, faça GETpara /user/:ide /song/:idpara cada usuário e ID da música para obter informações sobre o usuário e a música.
  2. GETpara /streamse buscar uma lista de todos os user_idse song_ids. Então, um GETpara /user?ids=<comma_separated_ids>buscar informações sobre todos os usuários e um GETpara song?ids=<comma_separated_ids>buscar informações sobre todas as músicas.
  3. GETpara /streamsbuscar tudo em uma chamada. Algo como -

    [
    
      {
    
        "user_id" : 10,
        "song_id" : 14,
        "listen_count" : 5,
        "user" : {
          "id"     : 10,
          "name"   : "bla", 
          "email"  : "bla",
        },
        "song" : {
          "id"     : 14,
          "name"   : "blu",
          "album"  : "blu"
       }
      },
    ...
    ]
    

Sinto-me tentado a optar pela opção 3 porque ela me dá tudo em uma ligação, mas não acho que seja muito tranquila e temo que não seja escalável. A opção 2 é boa, mas são necessárias três chamadas, o que significaria um tempo considerável para carregar a lista. E a opção 1 segue o resto, mas atenderá inúmeras chamadas para mostrar a lista e fazer tantas chamadas de um dispositivo móvel não é viável.

Qual seria a maneira recomendada de fazer isso?

aandis
fonte
Rest-like e vendable são duas coisas diferentes.
Robert Harvey
@RobertHarvey, como assim?
aandis
O que faz você pensar que a qualidade da sua interface REST afeta a capacidade de venda de um produto? Você está realmente vendendo a interface REST? Se você não é, ninguém se importa com o que está por trás. Veja também meta.stackexchange.com/q/142353
Robert Harvey
1
Há uma sobrecarga significativa ao fazer uma chamada REST. Conseqüentemente, há uma forte possibilidade de que 3 seja a melhor abordagem do ponto de vista da escalabilidade, especialmente se você usar todos os dados retornados.
Robert Harvey
1
Relacionados de uma forma programmers.stackexchange.com/q/257408/56903
toniedzwiedz

Respostas:

6

Ao criar uma interface REST, não há nenhum requisito, ou mesmo expectativa, de que as respostas na interface REST correspondam diretamente às tabelas ou junções no banco de dados.

Sua /streamsinterface pode ser tão facilmente representada quanto

[
  {
    "listen_count" : 5,
    "user" : {
      "href"     : "/users/10",
      "name"   : "bla", 
    },
    "song" : {
      "href"     : "/songs/14",
      "name"   : "blu",
      "album"  : "blu"
    }
  },
  ...
]

Onde os objetos JSON contêm os principais detalhes de usuários e músicas que são (quase) sempre relevantes para os consumidores de um recurso de fluxo e um link para os recursos relevantes de usuário / música, se mais detalhes forem necessários.

Essa é essencialmente uma variação da sua terceira opção, com um substituto para a opção 1, se mais detalhes forem necessários.

Bart van Ingen Schenau
fonte
Não há resposta garantida para mim, pessoal ... a opção 3 pode ser simples se os domínios continuarem simples, mas você terá problemas para objetos que contemplam mais de dois níveis de agregação. Por exemplo, você deseja recuperar todos os cursos disponíveis com os dados do professor. Você tem Course-> Teacher(informações sobre a pessoa como professor, armazenadas em uma tabela separada) -> Person(a pessoa física, como você pode se lembrar, a mesma pessoa pode ser professora de vários cursos). A opção 2 é escalável e requer * solicitação. Também optar. 1 também é escalável, mas pode precisar de >> solicitação.
Victor
Então, para sintetizar o comentário acima: se você procura eficiência, procure o número 1, mas se procura um sistema que possa crescer sem problemas no tempo (escalabilidade) sem causar dor de cabeça, procure as opções 1 ou 2. Vale a pena a menção de que optimiization prematura é a raiz do mal ... assim que este está advertindo para a opção 3.
Victor
necessidade de corrigir-me acima .. "se você olhar para a eficiência, em seguida, se esforçam para o número 3"
Victor
3

Você definitivamente deseja uma GEToperação única que retorne metadados sobre cada música e usuário, além de seus IDs opacos.

  • Como você apontou, é muito mais simples. Isso é uma coisa boa.
  • Tornar uma das operações mais comuns para seus aplicativos clientes uma solicitação de servidor único em vez de O (n) solicitações é muito mais escalável. A longo prazo, a rede será o seu maior gargalo, portanto, você não deseja enviar mais solicitações do que precisa.
  • Os IDs por si só são meio inúteis, exceto para fazer chamadas REST adicionais.
  • Contanto que seus metadados tenham um tamanho relativamente pequeno e limitado (por exemplo, nenhuma página de texto descritivo ou arquivos de áudio reais, apenas nomes, tipos, contagens etc.), devolvê-los além dos IDs provavelmente não será um problema de desempenho.
Ixrec
fonte
Interessante. Mas a opção 3 realmente não adere a um rest-fulldesign, não é? A GETto streams deve retornar todo streamse nada mais (mesmo que sejam apenas ids e inúteis para o cliente).
aandis 28/08
2
@zack No sentido estrito, sim, mas qualquer princípio de design pode ser levado longe demais. Quando você se encontra argumentando que o programa deve fazer algo inútil , isso geralmente não é um bom sinal.
Ixrec 28/08/2015
Metadados são dados sobre dados, são apenas dados.
Jacob Raihle 28/08/2015
@zack: Um streamsrecurso pode conter logicamente (partes de) outros recursos. Coisas que são logicamente parte de um recurso devem estar presentes na representação desse recurso.
Bart van Ingen Schenau 28/08/2015
1
A opção 3 do @zack é totalmente 100% RESTful. Os Recursos que você expõe por meio de sua API não exigem nenhum requisito para se relacionar com qualquer outra coisa em seu sistema, incluindo suas tabelas de banco de dados e seu modelo de domínio. Você poderia ter 3 tabelas de banco de dados e 600 recursos, se isso fizesse sentido para seu aplicativo Web. Não há nenhum requisito para representar seus relacionamentos com o banco de dados nos relacionamentos de Recursos.
Cormac Mulhall