API REST - A API deve retornar objetos JSON aninhados?


37

Quando se trata de APIs JSON, é uma boa prática achatar respostas e evitar objetos JSON aninhados?

Como exemplo, digamos que temos uma API semelhante à IMDb, mas para videogames. Existem algumas entidades, Game, Platform, ESRBRating e GamePlatformMap, que mapeiam Jogos e Plataformas.

Digamos que você solicite / game / 1, que busca o ID do jogo 1 e retorna o objeto do jogo com as plataformas e esrbRating aninhado.

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": [
    {"id":1,"name":"Xbox"},
    {"id":2,"name":"Playstation"}
  ],
  "esrbRating": {
    "id": 1,
    "code": "E",
    "name": "Everyone"
  }
}

Se você estiver usando algo como JPA / Hibernate, isso poderá ser feito automaticamente se estiver definido como FETCH.EAGER.

A outra opção é simplesmente a API e adicionar mais pontos finais.

Nesse caso, quando / game / 1 for solicitado, apenas o objeto do jogo será retornado.

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
}

Se você quiser as plataformas e / ou ESRBRating, precisará chamar o seguinte:

/ jogo / 1 / plataforma / jogo / 1 / esrb

Parece que esse método pode adicionar várias chamadas ao servidor, dependendo de quais dados o cliente precisa e quando precisa.

Houve um último pensamento que tive onde você teria algo assim retornado.

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": ["Xbox","Playstation"]
}

No entanto, isso pressupõe que eles não precisam dos IDs ou de qualquer outra informação que possa estar associada a esses objetos de plataforma.

Pergunto em geral qual é a melhor maneira de estruturar seus objetos JSON retornados da sua API. Você deve tentar ficar o mais próximo possível das suas entidades ou é bom usar objetos de domínio ou objetos de transferência de dados? Entendo que os métodos terão compensações, mais trabalho na camada de acesso a dados ou mais trabalho para o cliente.

Também gostaria de ouvir uma resposta relacionada ao uso do Spring MVC como a tecnologia de back-end da API, com JPA / Hibernate ou MyBatis para persistência.


6
Quais objeções, se houver, você tem retornando objetos incorporados? Retornar objetos incorporados individualmente de diferentes pontos de extremidade será bastante irritante (para não mencionar lento).
Robert Harvey

11
Pessoalmente, não tenho objeções. Só não estou ciente do que é considerado uma boa prática. Um colega afirma que trabalhar com objetos incorporados no AngularJS não é direto e, eventualmente, eu gostaria que o aplicativo Ember of AngularJS consumisse a API. Não sei o suficiente sobre a Angular ou a Ember para saber se isso terá um impacto ou não.
Greyfox

3
A resposta vai depender se você deseja retornar objetos de domínio, DTOs, objetos ViewModel ou objetos KitchenSink. Qual objeto que você está retornando provavelmente será determinado pelo que seu aplicativo precisa e como esse objeto se comporta na Internet. Exemplo: se você estiver tentando preencher uma página da Web com dados de uma fatura, provavelmente retornará um objeto contendo tudo o que precisa (a menos que planeje fazer AJAX nos itens de linha ou algo assim).
Robert Harvey

Nesse caso, quando você solicita um jogo, provavelmente deseja conhecer os gêneros, plataformas e ESRBRating. Isso faz sentido. Em termos de design, da perspectiva Java, você recomendaria ter o pacote Entity que possui JPA e, em seguida, um pacote de domínio que é o DTO / objetos de negócios retornando ao usuário?
Greyfox

11
As chamadas para o servidor são caras. Uma API que exige que você envie dados usando várias chamadas será mais lenta que uma API que permite obter tudo em uma chamada, geralmente mesmo quando a última retorna informações desnecessárias.
Gort the Robot

Respostas:


11

Outra alternativa (usando HATEOAS). Isso é simples, principalmente na prática, você adiciona uma tag de links no json, dependendo do uso do HATEOAS.

http://api.example.com/games/1:

{
  "id": 1,
  "title": "Game A",
  "publisher": "Publisher ABC",
  "developer": "Developer DEF",
  "releaseDate": "2015-01-01",
  "platforms": [
    {"_self": "http://api.example.com/games/1/platforms/53", "name": "Playstation"},
    {"_self": "http://api.example.com/games/1/platforms/34", "name": "Xbox"},
  ]
}

http://api.example.com/games/1/platforms/34:

{
  "id": 34,
  "title": "Xbox",
  "publisher": "Microsoft",
  "releaseDate": "2015-01-01",
  "testReport": "http://api.example.com/games/1/platforms/34/reports/84848.pdf",
  "forms": [
    {"type": "edit", "fields: [] },
  ]
}

É claro que você pode incorporar todos os dados em todas as listagens, mas isso provavelmente será um excesso de dados. Dessa forma, você pode incorporar os dados necessários e, em seguida, carregar mais, se realmente quiser trabalhar com eles.

A implementação técnica pode conter armazenamento em cache. Você pode armazenar em cache os links e nomes das plataformas no objeto do jogo e enviá-lo instantaneamente sem precisar carregar a API da plataforma. Então, quando necessário, você pode carregá-lo.

Você vê, por exemplo, que adicionei algumas informações de formulário. Fiz isso para mostrar que pode haver muito mais informações em um objeto json detalhado do que você gostaria de carregar na lista de jogos.


Eu não acho que isso seja tecnicamente HATEOS, já que não há estado.
precisa saber é o seguinte

Sim, não tenho certeza da palavra exata sobre esse processo. O HATEOS em geral está sendo usado para vincular as APIs restantes, mas concordo que também tenha a ver com o estado. Embora a ideia de implementação seja a mesma. Aqui você vê um pouco mais sobre como ele pode ser usado por um exemplo: stormpath.com/blog/linking-and-resource-expansion-rest-api-tips
Luc Franken

É uma boa ideia!
RibaldEddie

11
Se você estiver desenvolvendo uma API em que haja coesão entre o cliente e a própria API (por exemplo, uma API interna), pode fazer mais sentido retornar uma resposta aninhada (ou nivelada) em vez de fornecer links para outro recurso, o que significa mais solicitações de API o que pode ser indesejável.
de Bruno

@bruno sim, mas com um limite: em sistemas maiores, você não pode ou não deseja fornecer todos os objetos relacionados por completo. Os campos que você inclui por padrão são arbitrários; é possível selecioná-los com base no uso da sua API. Portanto, nesse caso, você pode ter plataformas com centenas de campos, o caso de uso está mostrando uma caixa de seleção para escolher uma plataforma. Então faz sentido incluir o nome da plataforma, mas não precisa dos detalhes financeiros da plataforma, por exemplo.
Luc Franken

16

Essa é uma dessas perguntas básicas quando se trata do design da API REST. Todo designer se faz essa pergunta no primeiro dia. Desculpe, mas a resposta é "depende". Cada abordagem tem prós e contras e você só precisa tomar uma decisão e seguir em frente.


10
Isso não é de todo útil. O próprio OP sabia "depende e cada abordagem tem prós e contras". Você deve explicar de que coisas isso depende ou, pelo menos, dar um exemplo.
Pratik Singhal

5

Segundo a abordagem apresentada aqui https://www.slideshare.net/stormpath/rest-jsonapis

Em resumo, inclua o recurso aninhado como links no recurso pai, enquanto isso, forneça um parâmetro de expansão no terminal pai.

Na minha opinião, essa é uma maneira eficiente e flexível na maioria dos casos.


2
Eu gosto dessa abordagem. Para quem se pergunta, isso começa no SLIDE 57 na apresentação de slides vinculada.
Adam Plocher
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.