Imagine uma API para identificar se uma pessoa selecionou seu animal espiritual. Eles só podem ter zero ou um animal espiritual.
Atualmente:
/person/{id}/selectedSpiritAnimal
quando eles selecionam um animal retorna http 200 e {selectedAnimal:mole}
mas quando eles não têm seleção, ele retorna http 404.
Isso deixa meu animal espiritual infeliz, pois estamos representando uma preocupação válida de domínio - ainda não tendo selecionado um animal espiritual - como um erro HTTP.
Além disso, como empresa - erm Sprit-Animal-Hampers-R-us - queremos saber quando alguém não tem seleção para que possamos solicitá-la.
Qual é a melhor resposta aqui:
HTTP 200 e {selectedAnimal:null}
ou ainda mais explícito
HTTP 200 e {selectedAnimal:null, spiritAnimalSelected: false}
Ou é melhor retornar um 404? Já que muito parecido this image has not yet been uploaded
ao visualizar uma imagem on-line seria um 404. this person has not selected a spirit animal
pode ser um 404
Esta pergunta foi proposta como duplicada, mas trata de uma URL válida, caso contrário, sendo solicitada quando o aplicativo foi configurado para não permitir a alteração que a URL representa.
Considerando que aqui eu estou olhando como alguém representa um recurso em que a ausência do recurso é significativa. Ou seja, é válido que o cliente solicite a URL e a resposta é que você solicitou com êxito o recurso que representa a ausência de algo.
Portanto, isso não é 'lógica de negócios', mas uma circunstância em que a ausência de algo tem significado (pode ser que muitos de meus colegas estejam argumentando que 404 ainda está correto), mas não tenho certeza de como mapear isso para o spec.
Muito difícil escolher uma resposta. Mudei de idéia várias vezes ao longo da conversa aqui e da que está em andamento no trabalho.
O que resolve isso aqui para mim é que a especificação diz que 4xx é quando o cliente cometeu um erro . Nesse caso, o cliente foi instruído a esperar uma resposta do URL selectedSpiritAnimal, para que não tenha errado.
O consenso entre meus colegas é de que isso é um sintoma de um mau design de API
Provavelmente seria melhor simplesmente solicitar / person / {id} e retornar um conjunto de relações de link para a pessoa ... se você não receber o link / selectedSpiritAnimal (quando uma pessoa não tiver seleção), mas você chame assim mesmo, então um 404 faz sentido. Ou que você implemente respostas parciais e deixe / person / {id} retornar um documento mais completo, a menos que o cliente solicite um subconjunto dos dados
Respostas:
Os códigos HTTP 4xx provavelmente não são a escolha certa para esse cenário. Você declara que ter animais com espírito zero é um estado válido, e a rota da API
person/{id}/selectedSpiritAnimal
explica se a pessoaid
possui ou não um.As respostas HTTP 4xx são reservadas para a situação em que um cliente fez algo incorreto na solicitação (consulte o arquivo w3 da especificação original ). Mas o cliente está fazendo uma solicitação válida, independentemente de a pessoa
id
ter ou não um animal espiritual.Então, eu me inclino para as segundas soluções usando um corpo JSON formatado corretamente na resposta e um código HTTP 2xx.
Agora, se você receber uma solicitação desse tipo e a pessoa
id
não existir, um código 4xx fará mais sentido.fonte
cases in which the client seems to have erred
, mas, por outro, o 404 diz diretamenteThe server has not found anything matching the Request-URI
. Você pode solicitar algo que não exista um erro do cliente. Entendo que a pessoa não existe vs um subprop não existe, mas isso pode ser indicado como mensagem de resposta. 204 também parece relevante, uma vez que a entidade existe, mas não possui conteúdo para uma subpropriedade.Deixe-me apresentar-lhe o Modelo de Maturidade de Richardson .
Seu problema é que você está representando dois recursos como um, onde realmente deve ter dois recursos que tenham um relacionamento indicado pela hipermídia. Usar a hipermídia para descrever relacionamentos é o glorioso nível 3 do Descanso.
Sua pessoa deve viver sob o URI
/person/{id}
e o animal deve viver sob/spiritanimal/{id}
. A pessoa deve indicar que possui um espírito animal usando um link para o animal.Vamos imaginar uma pessoa chamada Bob, que tem id 123 e um animal espiritual de unicórnio.
GET /person/123
retornaria;
Agora, quem lê a pessoa 123 saberá que tem um animal espiritual e possui o URI onde poderá obter mais informações.
GET /spitiranimal/789
pode retornar
Agora vamos imaginar uma pessoa chamada Fred, que tem o ID 456 e nenhum animal espiritual.
GET /person/456
retornaria;
Agora, quem lê a pessoa 456 saberá que não tem animal espiritual, pois não há vínculo. Não há necessidade de usar nenhum código de status HTTP para representar a falta de um relacionamento.
fonte
Este é o URL apropriado para obter animais espirituais; portanto, um erro 404 é inadequado. 404 é para representar um problema técnico, não um problema de lógica.
A solução apropriada é retornar http 200 e
{"selectedAnimal": null}
Você deve ter um método da web separado
/person/{id}/hasSelectedSpiritAnimal
que retorne{"isSpiritAnimalSelected": false}
. Nos bastidores, ele pode ou não fazer as mesmas chamadas de método, retornando false se nulo, mas cabe a ele decidir, não o código consumidor.É melhor evitar a combinação de consultas separadas em um método da Web sem um motivo convincente para fazê-lo, mesmo se as consultas estiverem intimamente relacionadas.
fonte
When you said "the spirit animal is not currently on file", it seemed quite similar to me to "there is no content"
Nenhum conteúdo significa nenhum conteúdo . ou seja: retorna "". Esses dois não são parecidos. "o animal espiritual não está no arquivo" é muito diferente de "".O que seu endpoint representa não é apenas um animal; é um animal ou falta dele. É um valor melhor representado por um
Optional
/Maybe
/Nullable
/ etc.Portanto, valores legítimos (como em 200 OK) podem ser:
{'animal': <some animal>, 'selected': true}
{'animal': null, 'selected': false}
Eu poderia imaginar isso
DELETE
método, quando aplicado ao ponto de extremidade, pode definir'selected'
afalse
novamente, isto é, retirar a animal seleccionado.Você pode, é claro, soltar a
'selected'
chave aqui, ela é mostrada apenas para maior clareza; string vsnull
é suficiente para a distinção.fonte
Você deve usar 404.
Como você está criando uma interface de programação, não uma interface humana, o texto 404 é opcional.
Eu prefiro isso porque prefiro protocolos padrão, tanto quanto possível. O HTTP tem uma maneira de representar a inexistência, e é isso que eu usaria.
EDIT: Suponha que você tenha adicionado um recurso em que os usuários possam escolher se desejam compartilhar seus animais espirituais e alguém não o compartilhar. Você retornaria 200 OK
null
ou 200 OK"Unauthorized
? Ou você usaria o padrão 401 Não Autorizado / 403 Proibido? Isso parece diretamente análogo a não escolher um em primeiro lugar.Como alternativa, se você quiser usar 200 OK + JSON, retorne
null
.Mantenha as coisas limpas. Crie mais quebra automática apenas se necessário.
fonte
null
(não têm valor). Isso é diferente do cliente que solicita algo para o qual não existe slot para armazenar o valor. Você não sugere jogar umAttributeError
em Python quando o valor éNone
; isso tornaria a interface impraticável e desnecessariamente difícil de trabalhar. Mais pragmaticamente, muitas APIs de clientes HTTP podem converter o 404 no mecanismo de tratamento de erros padrão do idioma (código de erro, exceção, tipo de erro), o que significa que você precisará suprimir um erro estranho./person/{id}/selectedSpritAnimal
, observe o erro de digitaçãoSprit
)./person/{id}/isSpiritAnimalSelected
que indique ao cliente se um foi selecionado. Parece-me o mesmo exemplo clássico de testar se existe um arquivo antes de lê-lo. Basta ler o arquivo e manipular o erro ENOENT, caso seja lançado./person/{id}/selectedSpiritAnimal
deve ser usado mesmo que o animal espiritual não exista. Isso significa que o HTTP 4xx está incorreto, quando usado nesse caso. Op também afirma corretamente que isso pode ser um cheiro de mau design da API.