Design de API RESTful. O que devo retornar se não houver linhas?


50

Atualmente, estou codificando uma API para uma rede social com o Slim Framework. Minha pergunta é: Quais são as práticas recomendadas quando não há linhas para retornar na estrutura json?

Digamos que esta chamada / v1 / get / movies retorne 2 linhas dos nomes dos filmes da tabela:

[
    {"name": "Ghostbusters"},
    {"name": "Indiana Jones"}
]

Mas eu chamo / v1 / get / books e não há linhas nessa tabela. Devo apenas retornar uma estrutura vazia?

[
]

... ou seria melhor uma mensagem e um código de erro?

[
    "errors": {
        "message": "no matches found",
        "code": 134
    }
]

Qual é uma prática melhor? (a API será usada em aplicativos iOS e Android) Obrigado!


3
Para mim, isso parece a questão de saber se zero é realmente uma quantia.
Scarfridge 29/05

16
Seu exemplo está quebrado. Você não pode ter objetos json com chaves duplicadas. O que você está procurando é um array, ou seja[{"name": "..."}, {"name":"..."}]
Martin Wickman

@MartinWickman Desculpe por isso, eu apenas consertei.
Andres SK

8
@andufo, na verdade, você não ...
avakar

25
Se seu aplicativo deve ser RESTful, por que o verbo / método "get" faz parte do seu URI do terminal?
User50849

Respostas:


46

Normalmente, eu retornaria o número de registros no resultado como metadados. Não tenho certeza se isso é prática REST normal, mas não há muitos dados extras e é muito preciso. Geralmente, há paginação para muitos serviços; é impraticável retornar um grande conjunto de resultados de uma só vez. Pessoalmente, fico chateado quando há paginação para pequenos conjuntos de resultados. Se estiver vazio, retorne number_of_records : 0e registre como lista / matriz vazia books : [].

{
    meta: {
        number_of_records : 2,
        records_per_page : 10,
        page : 0
    },
    books : [
        {id:1},
        {id:27}
    ]
}

EDIT (alguns anos depois): A resposta de Martin Wickman é muito melhor, aqui está "breve" a explicação do porquê.

Ao lidar com paginação, lembre-se sempre da possibilidade de conteúdo ou alteração de ordem. Como, a primeira solicitação chega, 24 resultados, você retorna primeiro 10. Depois disso, "novo livro" é inserido e agora você tem 25 resultados, mas com a solicitação original, ela seria solicitada em 10º lugar. Quando o primeiro usuário solicita a segunda página, ele não recebe "novo livro". Existem maneiras de lidar com esses problemas, como fornecer "ID da solicitação", que deve ser enviado com as seguintes chamadas da API e retornar a página seguinte do conjunto de resultados "antigo", que deve ser armazenado de alguma forma e vinculado à "ID da solicitação". Alternativa é adicionar um campo como "lista de resultados alterada desde a primeira solicitação".

Geralmente, se você puder, tente fazer um esforço extra e evitar a paginação. A paginação é um estado adicional que pode ser modificado e o rastreamento dessas alterações é suscetível a erros, ainda mais porque o servidor e o cliente precisam lidar com isso.

Se você tiver muitos dados para processar de uma só vez , considere retornar a "lista de identificação" com todos os resultados e detalhes para alguns trechos dessa lista e forneça chamadas de API multi_get / get_by_id_list para obter recursos.


11
Ah, eu me pergunto por que este não é votado tão bem quanto o outro. Eu gosto mais disso, pois está fornecendo uma lista vazia (que deveria ser uma lista, certo?) Que você pode iterar cegamente sem condições especiais, mas também os metadados contam como uma maneira de dizer: "Não, nós não ' Para ocultar um erro, na verdade houve 0 resultados ".
30713 Izkata

11
-1 porque o booksparâmetro é um objeto, mas 'books' implica mais de um e mais de um implica array. Os metadados são legais e quase todos, mas eu esperaria que uma coleção de livros fosse uma variedade de objetos de livros; se não houver livros apenas dar-me a matriz vazia
Charles Sprayberry

9
O problema é que a adição de "number_of_records" não fornece mais informações, apenas adiciona redundância e aumenta a complexidade. Para sinalizar um erro, retorne um código http adequado + algo no corpo.
Martin Wickman

11
@cspray books é uma lista, como Izkata apontou, meu erro de digitação.
Grizwako

2
@MartinWickman Eu não queria poluir a resposta original com metadados extras, mas na minha experiência, muitos serviços não retornam todos os dados imediatamente, mas de maneira "paginada".
Grizwako

105

Seu exemplo está quebrado. Você não deve ter objetos json com chaves duplicadas. O que você está procurando é uma matriz com objetos de filme, como este:

 [
    {"name": "movie1"}, 
    {"name": "movie2"}
 ]

Essa abordagem também responde à sua pergunta. Você deve retornar uma matriz vazia quando a consulta não corresponder:

[]

Por outro lado, se você tentar obter um recurso de filme específicoGET api/movie/34 e esse filme não existir, retorne 404 com uma mensagem de erro adequada (codificada por json) no corpo


11
+1 Este é JSON válido de acordo com json_xs.
l0b0

15

Se esse é JSON, você deve considerar retornar uma matriz de objetos. Isso tem muitas vantagens, incluindo que, quando você não possui registros, é uma matriz vazia.

Então, quando você tiver registros, retornaria:

    [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]

E quando você não possui registros, retornaria:

    [

    ]

14

Se você executar a operação com êxito, mas ela não tiver nada para retornar, como mapa vazio {}ou matriz vazia, []eu preferiria responder com o código de resposta 204, aqui está um trecho da especificação das Definições de Código de Status HTTP :

O servidor atendeu à solicitação, mas não precisa retornar um corpo de entidade e pode querer retornar metainformações atualizadas. A resposta PODE incluir metainformações novas ou atualizadas na forma de entidades-cabeçalhos, que, se presentes, DEVERÃO estar associados à variante solicitada.

Se o cliente é um agente de usuário, ele NÃO DEVE alterar sua exibição de documento daquela que causou o pedido a ser enviado. Esta resposta destina-se principalmente a permitir a entrada de ações a serem realizadas sem causar uma alteração na exibição do documento ativo do agente do usuário, embora qualquer metainformação nova ou atualizada DEVE ser aplicada ao documento atualmente na exibição ativa do agente do usuário.

A resposta 204 NÃO DEVE incluir um corpo da mensagem e, portanto, é sempre encerrada pela primeira linha vazia após os campos do cabeçalho.

Basicamente, recomendo usar 204 em aplicativos RESTful por HTTP quando não houver nada a retornar.


4
Concordo com o comentário de @ avakar em outra resposta aqui. Se o cliente está tentando acessar / v1 / get / movies / 1, ele deve retornar 404 se não houver filmes identificáveis ​​por 1. Apenas / v1 / get / movies deve retornar 200 mesmo se não houver filme. Mas 204 não é adequado porque se destina a ações de entrada.
Imel96 30/05

7
Outro problema com esta solução é que ela normalmente precisará de um código especial no cliente: se a resposta for uma lista vazia, ela poderá ser analisada como JSON, como uma resposta normal. Se a resposta for um corpo vazio, o analisador JSON provavelmente reclamará (porque um documento vazio não é JSON válido); portanto, o cliente precisa de código extra para verificar o HTTP 204 e ignorar a análise.
Sske

7
Acredito que essa é uma leitura incorreta da intenção do 204. 204 parece não ser destinado a operações que esperavam conteúdo e não conseguiram encontrar nenhum, mas sim a operações que foram bem-sucedidas e não tiveram retorno pretendido . Da Wikipedia: "O servidor processou a solicitação com êxito, mas não está retornando nenhum conteúdo. Geralmente usado como resposta a uma solicitação de exclusão bem-sucedida."
XML

10

Houve uma quantidade razoável de trabalho realizado na criação de um formato de API JSON padronizado .

Seguir os princípios dessa especificação significa que todos os recursos retornados devem efetivamente ser "coleções" (mesmo quando apenas um único recurso é incluído). Após isso, sua chamada para /v1/get/moviesretornará:

{
    "movies": [
        {"name": "Ghostbusters"},
        {"name": "Indiana Jones"}
    ]
}

Sua chamada para /v1/get/books(que retorna zero recursos) retornaria:

{
    "books": []
}

5

Para seu exemplo específico, eu recomendaria que / v1 / get / books retornasse HTTP 200 com uma matriz vazia.

Se estou lendo sua postagem corretamente, sua API pretende coletar livros. Metaforicamente, você tem uma estante de livros, um rack de DVD para filmes e possivelmente outros recipientes que você não mencionou aqui. Como você pretende coletar livros, / v1 / get / books é sua estante de livros. Isso significa que existe um recurso válido - uma lista de livros - que está vazia no seu exemplo específico.

O motivo pelo qual não sugiro retornar HTTP 404 nesse caso é que a estante de livros ainda está lá. Não há livros no momento, mas ainda é uma estante de livros. Se não fosse uma estante de livros - se a API não pretendesse coletar livros, por exemplo - , o HTTP 404 seria apropriado. Mas como há um recurso lá, você não deve sinalizar que não existe, o que o HTTP 404 faz. Portanto, argumento que 200 com uma matriz vazia (significando a coleção) é mais apropriado.

O motivo de eu não sugerir o retorno do HTTP 204 é que isso sugere que "Nenhum Conteúdo" é o estado comum: a execução dessa ação nesse recurso normalmente não retornaria nada. É por isso que geralmente é usado como resposta a solicitações DELETE, por exemplo: a natureza da exclusão geralmente significa que não resta nada para retornar. O caso é semelhante quando é usado para responder a solicitações com a família de cabeçalhos If-Modified: você só queria conteúdo se o recurso tivesse mudado, mas não mudou, por isso não darei a você nenhum conteúdo.

Mas eu argumento que, para OBTER uma coleção vazia mas válida, o HTTP 204 não faz sentido. Se houvesse itens na coleção, a representação adequada seria uma matriz desses dados. Portanto, quando não há dados (mas a coleção é válida), a representação adequada é uma matriz vazia.


5

Você realmente deve fazer apenas uma das duas coisas

Retorne um 200 (OK)código de status e uma matriz vazia no corpo.

Ou Retorne um 204 (NO CONTENT)código de status e nenhum corpo de resposta.

Para mim, a opção 2 parece mais tecnicamente correta e alinhada com os princípios REST e HTTP.

No entanto, a opção 1 parece mais eficiente para o cliente - porque o cliente não precisa de lógica extra para diferenciar entre dois códigos de status (bem-sucedidos). Como sabe que sempre receberá uma matriz, basta verificar se não possui nenhum, um ou muitos itens e processá-la adequadamente.


3

Eu já vi os dois casos em ambientes de produção. Qual você escolhe depende de quem usará a API. Se eles querem saber por que a lista está vazia ou para ter certeza de que a lista está realmente vazia e nenhum erro ocorreu durante a recuperação, você deve anexar um objeto "erros". Se eles não se importam, retorne uma lista vazia. Eu iria com a segunda abordagem, uma vez que abrange mais necessidades do que a primeira.


3

A primeira coisa a considerar, desde que você esteja criando uma API RESTful, é retornar um código de resposta apropriado. E o código de resposta mais apropriado para comunicar que a solicitação foi executada normalmente, mas o recurso solicitado não está disponível no momento é o venerável 404.

Se você projetar sua API de forma que ela sempre retorne um código de resposta sensato, talvez você nem precise retornar um corpo quando o recurso não foi encontrado. Dito isto, devolver um corpo, especialmente um humanamente legível, não pode machucar.

Não há "boas práticas" aqui, os dois exemplos são arbitrários, basta escolher uma e ser consistente . Os desenvolvedores odeiam surpresas, se /v1/get/moviesretornarem {}quando não houver filmes, esperaríamos /v1/get/actorstambém retornar {}quando não houver atores.


11
Devolver um 404 é realmente a coisa certa a se fazer, mas infelizmente ninguém o faz - inclusive eu.
RibaldEddie

11
se você tiver respostas complexas e apenas partes delas estiverem vazias, retornar um 404 confundirá o usuário.
devnull 29/05

5
Eu discordo da mensagem 404. Um 404 eu interpretaria como "o recurso não existe" e me preocuparia se tivesse algo errado com minha URL ou o que quer. Se eu pedir uma lista de filmes e conseguir um 404, acho que não há um recurso de filme. Um "204 sem conteúdo" pode ser mais apropriado.
275133 Thorsten

8
Ok, a coisa "sem corpo" a mataria. Mas: "A classe 4xx do código de status é destinada a casos em que o cliente parece ter errado.". Mas não houve erro no lado do cliente. Portanto, um 404 fornece informações erradas. Envie 204 sem um corpo ou diga que está tudo bem e envie uma lista vazia.
275133 Thorsten

9
Você está pedindo uma lista de livros. O retorno de 404 significa que a lista não existe, e não está vazia. Devolver 200 junto com uma lista vazia parece a única opção razoável para mim.
Avakar 29/05

1

Não acho que a resposta certa seja a que está marcada.

A resposta fornecida pelo nirth deve ser a melhor, em um verdadeiro cenário REST. A resposta do corpo deve estar vazia e o código de status http: 204; o recurso existe, mas não tem "conteúdo" naquele momento: está vazio.

HTTP_Status_Codes REST


1

Eu recomendo 200 + array vazio, pois simplifica o tratamento por todos os clientes da API. 200 + array significa "retornei todos os dados que estão lá". Tanto para o código que entrega os dados quanto para o código que os processa, o número de itens seria irrelevante.

Todos os outros códigos de status precisam ser adequadamente documentados, entregues adequadamente pelo servidor e processados ​​adequadamente pelo cliente, e todos sabemos a probabilidade de isso acontecer.

Houve uma sugestão para retornar o status 204 + corpo vazio. Isso significa que você forçar cada único cliente para status do processo 204 corretamente. Além disso, você os força a lidar com respostas não JSON! Espero que todos percebam que apenas porque uma solicitação obteve uma resposta, isso não significa que a resposta veio do servidor quando o http é usado e apenas uma verificação de que a resposta é JSON lida com muitos desses casos.


0

Eu "depende".

Se zero for um resultado razoável, retorne a lista vazia. Por exemplo, se você deseja que todos os funcionários sejam chamados "bob", onde "none" é um resultado bastante razoável. Se não for um resultado esperado, retorne um erro. Por exemplo, obter uma lista histórica de endereços de uma pessoa que você emprega. Eles devem morar em algum lugar para que nenhum resultado seja provavelmente um erro, não apenas uma condição normal.

Tenho certeza que você pode discutir com as especificidades do meu exemplo, mas você entendeu a ideia ...


0
  • Primeiro de tudo, ter getem sua URL não é RESTful, GET é implícito pelo método HTTP.
  • Se você estiver solicitando uma coleção como GET api/moviesretorne a 200 OKcom uma matriz vazia [].
  • Se você está solicitando um filme específico como GET api/movies/1(onde 1está o ID) e ele não existe, retorne a 404 Not Found.

Por quê? Você está solicitando recursos . Quando você está solicitando a coleção, o próprio recurso (a coleção) existe. Portanto, a 404está errado. Mas se você solicitar um filme específico e ele não existir, o recurso solicitado não existe e você deverá retornar a 404.


-2

Se você estiver retornando JSON, é melhor sempre retornar contagem e mensagem de erro e talvez um booleano que indique se há erro ou não, esse é o meu três valores meta padrão retornados com cada lista de linhas.

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.