Quando usar o código de status HTTP 404 em uma API


58

Estou trabalhando em um projeto e depois de discutir com as pessoas no trabalho por mais de uma hora. Decidi saber o que as pessoas na troca de pilhas poderiam dizer.

Estamos escrevendo uma API para um sistema, há uma consulta que deve retornar uma árvore da organização ou uma árvore de objetivos.

A árvore da organização é a organização na qual o usuário está presente. Em outras palavras, essa árvore sempre deve existir. Na organização, uma árvore de objetivos deve estar sempre presente. (foi aí que o argumento começou). Caso a árvore não exista, meu colega de trabalho decidiu que seria correto responder a resposta com o código de status 200. E então comecei a me pedir para corrigir meu código porque o aplicativo estava desmoronando quando não havia árvore.

Vou tentar poupar chamas e fúria.

Sugeri gerar um erro 404 quando não há árvore. Pelo menos, me informaria que algo está errado. Ao usar o 200, tenho que adicionar uma verificação especial à minha resposta no retorno de chamada de sucesso para lidar com erros. Estou esperando receber um objeto, mas posso receber uma resposta vazia porque nada foi encontrado. Parece totalmente justo marcar a resposta como 404. E então a guerra começou e recebi a mensagem de que não entendia o esquema do código de status HTTP. Então, eu estou aqui e perguntando o que há de errado com 404 neste caso? Eu até entendi o argumento "Não encontrou nada, então é correto retornar 200". Eu acredito que está errado, pois a árvore deve estar sempre presente. Se não encontramos nada e esperamos algo, deve ser um 404.

Mais informações,

Esqueci de adicionar os URLs que foram buscados.

Organizações

/OrgTree/Get

Metas

/GoalTree/GetByDate?versionDate=...
/GoalTree/GetById?versionId=...

Meu erro, ambos os parâmetros são necessários. Se qualquer versionDate que puder ser analisada até uma data for fornecida, ela retornará a revisão de fechamento. Se você digitar algo no passado, ele retornará a primeira revisão. Se por ID com um ID que não existe, suspeito que ele retornará uma resposta vazia com 200.

Extra

Além disso, acredito que a melhor resposta para o problema é criar objetos padrão quando as organizações são criadas, não ter árvore não deve ser um caso válido e deve ser visto como um comportamento indefinido. Não há como uma conta ser usada sem as duas árvores. Por esse motivo, eles devem estar sempre presentes.

também eu liguei isso (um semelhante, mas não consigo encontrá-lo)

http://viswaug.files.wordpress.com/2008/11/http-headers-status1.png


Esclareça: como o aplicativo pode desmoronar quando não há árvore, se há sempre uma árvore por pré-condição ? (Eu concordo com você parece um 404)
Andres F.

Bem, o código não estava checando um nulo e estava analisando uma string json e como um objeto. Em algum lugar do código, o objeto "carregado" não está presente porque não pode ser encontrado internamente.
Loïc Faure-Lacroix

4
Seria mais claro se você fornecer os URIs para o recurso que você está tentando acessar. Se for / goals / você retorna 200 e set vazio. Se você estiver tentando acessar / goals / {goal_id}, retornará 404. Se você retornou 404 para a solicitação de / goals /, significa que o URI não existe e não deve mais ser usado.
Imel96

11
Ainda em ambos os casos, a questão se mantém. O que deve /GoalTree/GetById?versionId=CompletelyInvalidIDretornar? Não foi bem-sucedido, pois o recurso chamado /GoalTree/GetById?versionId=CompletelyInvalidIDliteralmente não foi encontrado.

2
Ótimo, agora a discussão mudou do seu trabalho para os internets! É imparável agora!
Carlos Campderrós

Respostas:


80

Em caso de dúvida, consulte a documentação . A revisão das definições do W3C para códigos de status HTTP nos fornece o seguinte:

200 OK - A solicitação foi bem-sucedida. As informações retornadas com a resposta dependem do método usado na solicitação.

404 não encontrado - o servidor não encontrou nada que corresponda ao URI do pedido.

No contexto da sua API, depende muito de como as consultas são criadas e como os objetos são recuperados. Mas, minha interpretação sempre foi a seguinte:

  • Se eu pedir um objeto em particular e ele existir 200código de retorno , se ele não existir, retorne o 404código correto .
  • Mas, se eu pedir um conjunto de objetos que corresponda a uma consulta, um conjunto nulo é uma resposta válida e quero que seja retornado com um 200código. A lógica para isso é que a consulta era válida, foi bem-sucedida e a consulta não retornou nada.

Portanto, neste caso, você está correto , o serviço não está procurando por "uma coisa específica", está solicitando uma coisa em particular, se essa coisa não for encontrada, diga isso claramente.

Eu acho que a Wikipedia coloca da melhor maneira:

200 OK - ... A resposta real dependerá do método de solicitação usado. Em uma solicitação GET, a resposta conterá uma entidade correspondente ao recurso solicitado.

404 Não encontrado - O recurso solicitado não pôde ser encontrado, mas pode estar disponível novamente no futuro. Pedidos subsequentes do cliente são permitidos.

Parece muito claro para mim.

Em relação aos pedidos de exemplo

/GoalTree/GetByDate?versionDate=...
/GoalTree/GetById?versionId=...

Para o formato, você disse, sempre retorne a revisão mais próxima a essa data. Ele nunca não retornará um objeto, portanto sempre deve retornar 200 OK. Mesmo que isso pudesse levar um intervalo de datas, e a lógica seria retornar todos os objetos dentro desse prazo, retornando 200 resultados OK - 0 está ok, pois era para isso que era a solicitação - o conjunto de coisas que atendiam a esse critério.

No entanto, o último é diferente, pois você está solicitando um objeto específico , presumivelmente único, com essa identidade. O retorno 200 OKneste caso está errado, pois o recurso solicitado não existe e não foi encontrado .

Sobre a escolha de códigos de status

  • Códigos 2xx Diga a um UA que fez a coisa certa , a solicitação funcionou. Pode continuar fazendo isso no futuro.
  • Códigos 3xx Diga a uma UA o que você pediu provavelmente funcionava, mas essa coisa está agora em outro lugar. No futuro, o UA poderá considerar apenas redirecionar .
  • Códigos 4xx Diga a um UA que fez algo errado , a solicitação que ele construiu não é adequada e não deve tentar novamente, sem pelo menos algumas modificações.
  • Códigos 5xx Diga a um UA que o servidor está danificado de alguma forma . Mas, ei, essa consulta poderá funcionar no futuro, portanto, não há razão para não tentar novamente. (exceto o 501, que é mais um problema de 400).

Você mencionou em um comentário usando um código 5xx, mas seu sistema está funcionando. Foi solicitada uma consulta que não funciona e precisa comunicá-la ao UA. Não importa como você o corta, este é um território 4xx.

Considere um alienígena consultando nosso sistema solar

Alien: Computador, por favor me diga todos os planetas que os humanos habitam.

Computador: 1 resultado encontrado. Terra

Alien: Computador, por favor, conte-me sobre a Terra .

Computador: Terra - Principalmente inofensivo.

Alien: Computador, por favor, conte-me sobre todos os planetas que os humanos habitam, fora do cinturão de asteróides.

Computador: 0 resultados encontrados.

Alien: Computador, por favor destrua a Terra.

Computador: 200 OK.

Alien: Computador, por favor, conte-me sobre a Terra .

Computador: 404 - Não encontrado

Alien: Computador, por favor me diga todos os planetas que os humanos habitam.

Computador: 0 resultados encontrados.

Alien: vitória para o poderoso Império Irken!


4
+1 Esta não é uma consulta que não retorna resultados. É como pedir ao navegador uma página da web conhecida e não encontrá-la. Exatamente para que 404 existe.
Andrés F.

2
@ imel96 você esquece que a string de consulta faz parte da URL.
Loïc Faure-Lacroix

11
@LegoStormtroopr Seu exemplo "alienígena" divertido funciona porque o universo NÃO é inválido quando a Terra não existe. Mas, de acordo com a explicação do OP, seu sistema deve incluir a árvore. Sem árvore, o sistema não funciona.
Andres F.

11
@LegoStormtroopr imagine uma tabela de banco de dados. Você consulta a tabela, às vezes obtém resultado, às vezes não. A tabela é seu recurso, ela está sempre lá, independentemente de estar retornando linhas ou não. A tabela é identificável, possui nome (como os recursos http possuem URIs). As linhas não são, elas correspondem apenas a alguns parâmetros. Mesmo no banco de dados, se você fizer uma atualização que não corresponde a nada, receberá "OK 0 linhas afetadas".
Imel96 03/07/2013

2
@LegoStormtroopr você já tem a resposta. Se eles quiserem remapear / GoalTree / GetById? VersionId = x, retornará 301 com o cabeçalho Localização definido como / GoalTree / Id / x.
Imel96

11

Ignorando o fato de que / GoalTree / Get * parece um verbo, não recursos, você sempre deve retornar 200 porque o URI / GoalTree / Get * representa recursos sempre disponíveis para acesso e não é erro do cliente se não houver uma árvore como resultado de um pedido. Apenas retorne 200 com o conjunto vazio quando não houver nenhuma entidade a ser retornada.

Você usa 404 se o recurso não for encontrado, não quando não houver entidade.

Em outras palavras, se você quiser retornar 404 para seus objetos, forneça a eles seus próprios URIs.


11
Hmm. Isso faz sentido. 404 é um erro do usuário , mas, como o OP explica, esse é realmente um erro do sistema ; a solicitação do usuário é perfeitamente válida! Eu discordo que 200 é a resposta certa, porque "nenhuma árvore" é um erro .
Andres F.

@ imel96 Prefiro que entidades válidas sejam sempre retornadas em vez do código de status vazio 4xx / 5xx. Se fosse apenas eu, retornaria uma entidade válida, como um wiki, por exemplo. Menos dor de cabeça, não há necessidade de lidar com erros. Como é, eu diria que é quase um 500. O sistema está em um estado indefinido, não deveria acontecer. E voltar OK não faz sentido. 404 sobre o rfc também não faz sentido. Então, quando nada faz sentido ... apenas 500 fazem sentido!
Loïc Faure-Lacroix

@ Sybiam bem, você pediu o código de status http, que está muito bem definido. Nesse sentido, mesmo que sua lógica de negócios diga que é um erro, isso não significa que o sistema como um servidor http tenha um erro. No seu caso, ele entendeu sua solicitação, processou sua consulta e aconteceu que o resultado não é uma entidade. Portanto, você também não pode usar 500. Pelo menos, considere fornecer URIs apropriados aos seus objetos e veja se o rfc faz mais sentido ou não.
Imel96 03/07/19

+1 Se você tiver uma API REST (cada entidade possui seu próprio caminho), poderá retornar um 404, mas seus caminhos são verbos e sempre serão encontrados.
Pare de prejudicar Monica

@ OrangeDog: /GoalTree/GetById?versionId=12345 é um URI perfeitamente bom (bem, um relativo, pelo menos) que identifica um recurso específico, ou seja, os dados correspondentes ao ID da versão 12345no sistema. Se não houver dados com esse ID, uma resposta HTTP 404 é perfeitamente apropriada. Obviamente, o corpo da resposta deve, em qualquer caso, conter uma resposta formatada adequadamente (por exemplo, JSON, se é o que os clientes típicos que solicitam tais recursos esperam), indicando a natureza específica e a causa do erro.
Ilmari Karonen

7

Essa é uma pergunta interessante, porque é tudo sobre as especificações do sistema.

A resposta de imel96 me convenceu que um 404 não seria uma resposta adequada, pois a família de códigos 4xx é principalmente para erros de usuário / cliente , e esse não é um deles. O URL está bem formado e a árvore deve estar lá; caso contrário, o sistema está em um estado inconsistente!

Portanto, este é um erro do servidor , ou seja, algo da família 5xx. Possivelmente um erro interno de servidor 500 genérico ou um serviço 503 indisponível (o serviço sendo "me traga a árvore que deve estar lá").


2
Não é verdade, o usuário está errado porque pediu algo que não existe .

@LegoStormtroopr Pedir algo que não existe nem sempre é um erro. Se você solicitar um recurso de rede e a rede estiver inativa, será um erro de rede .
Andres F.

11
@LegoStormtroopr Além disso, a árvore deve existir; o sistema não pode funcionar sem ele, conforme explicação do OP. Portanto, é válido solicitar esse recurso; se não estiver lá, deve haver um erro no sistema (ou servidor).
Andres F.

2
@ Sybiam Se você deseja seguir a rota de um código 5xx, 503 é "Serviço 503 indisponível - o servidor não está atualmente apto a lidar com a solicitação devido a uma sobrecarga ou manutenção temporária do servidor". Seu servidor não está sobrecarregado, não está encontrando uma solicitação. Além disso, os códigos 5xx são para quando "o servidor está consciente de que errou ou é incapaz de executar o pedido"

11
@AndresF. Para ser honesto, um código 500 provavelmente está bom. Dado como a pergunta mudou com o tempo, ela funcionaria. Principalmente, estou me unindo contra o retorno de 200 se tudo não estiver bem.

6

Eu diria que um código de resposta 200 ou 404 pode ser válido , dependendo de como você olha a situação.

O problema é que os códigos de resposta HTTP são definidos no contexto de um servidor , que pode fornecer vários recursos com base em sua URL. Nesse contexto, os significados de 200 OKe 404 Not Foundsão perfeitamente inequívocos: o primeiro diz "aqui está o recurso que você solicitou", enquanto o segundo diz "desculpe, eu não tenho nenhum recurso como esse".

No entanto, na sua situação, você tem uma camada de aplicativo adicional entre o servidor HTTP e os recursos reais (árvores) que estão sendo solicitados. O aplicativo ocupa uma espécie de espaço intermediário que não é bem endereçado na especificação HTTP.

Do ponto de vista do servidor, o aplicativo parece tipo de como um recurso: é tipicamente um arquivo no servidor, identificado por (uma parte do) o URL, assim como outros recursos (por exemplo, arquivos estáticos) o servidor pode servir. Por outro lado, é um tipo estranho de recurso, uma vez que consiste em código executável que determina dinamicamente o conteúdo e, de fato, potencialmente até o código de status da resposta, fazendo com que ele se comporte de certa forma mais como um miniservidor.

Em particular, no seu exemplo de exemplo, o servidor da Web pode localizar o aplicativo perfeitamente, mas o aplicativo falha ao localizar o sub-recurso (árvore) solicitado. Agora, se você considera o aplicativo apenas uma extensão do servidor e o subitem (árvore) é o recurso real, uma resposta 404 é apropriada: o servidor apenas delegou a tarefa de localizar o recurso real no aplicativo , que por sua vez não conseguiu.

Por outro lado, se seu ponto de vista é que o aplicativo é o recurso que está sendo solicitado, obviamente o servidor da web deve retornar uma resposta 200 ; afinal, o aplicativo foi encontrado e executado corretamente. Obviamente, nesse caso, o aplicativo deve realmente retornar um corpo de resposta válido no formato esperado, indicando (usando qualquer protocolo de nível superior que esse formato codifique) que nenhum dado real correspondente à consulta foi encontrado.

Ambos os pontos de vista podem fazer sentido. Na maioria dos casos , pelo menos para aplicativos destinados a serem acessados ​​diretamente via HTTP com um navegador da Web comum, eu preferiria a visão anterior : o usuário geralmente não se importa com detalhes internos, como a diferença entre o servidor e o aplicativo, eles apenas se preocupam se os dados que eles querem estão lá ou não.

No entanto, no caso específico de um aplicativo projetado para se comunicar com outros programas de computador usando um protocolo API de alto nível personalizado, usando HTTP apenas como uma camada de transporte de baixo nível , há um argumento a ser adotado em favor dessa última visualização : Se os clientes fizerem interface com esse aplicativo, o que realmente interessa, no nível HTTP , é se eles conseguiram entrar em contato com o aplicativo ou não. Tudo o resto é, nesses casos, frequentemente comunicado de forma mais natural usando o protocolo de nível superior.


De qualquer forma, independentemente de qual das visualizações acima você preferir, há alguns detalhes que você deve ter em mente. Uma é que, em muitos casos, pode haver uma distinção significativa entre um recurso (essencialmente) vazio e um recurso inexistente .

No nível HTTP, um recurso vazio seria simplesmente indicado por um código de resposta 200 e um corpo de resposta vazio, enquanto um recurso inexistente seria indicado por uma resposta 404 e um corpo de recurso explicando a ausência do recurso. Em um protocolo API de nível superior, normalmente indica-se um recurso inexistente por uma resposta de erro, contendo um código / mensagem de erro específico do protocolo adequado, enquanto uma resposta vazia seria simplesmente uma estrutura de resposta normal sem itens de dados.

(Observe que um recurso não precisa ter literalmente zero bytes para ficar "vazio" no sentido que quero dizer acima. Por exemplo, um resultado de pesquisa sem itens correspondentes contaria como vazio no sentido amplo, assim como uma consulta SQL com sem linhas ou um documento XML que não contém dados reais.)

Além disso, é claro, se a aplicação realmente acredita que o subrecurso solicitado deve estar lá, mas não consegue encontrá-lo, em seguida, um terceiro código de resposta possível existir: 500 Internal Server Error. Essa resposta faz sentido se a existência do recurso for uma condição prévia assumida para o aplicativo, de modo que sua ausência indique necessariamente um mau funcionamento interno.

Por fim, você deve sempre ter em mente a lei de Postel :

" Seja conservador no que envia e liberal no que recebe. "

Se o servidor deve responder em uma situação particular com um 200 ou uma resposta 404, isso não é desculpa você como o cliente implementador do manuseamento quer resposta adequada e na forma que maximiza a interoperabilidade robusta. Obviamente, o que significa manipulação "apropriada" em diferentes situações pode ser discutido, mas certamente não deveria normalmente incluir falhas ou "desmoronar".


O dilema bem explicado.
Marcel

não há dilema. esta resposta não se baseia em qual recurso é definido como no rfc relacionado. veja meu comentário na resposta @LegoStormtroopr.
Imel96

@ imel96: Eu acho que você está interpretando mal a RFC 1630: o parágrafo que você cita no seu comentário anterior é o seguinte: "O ponto de interrogação ("? ", ASCII 3F hex) é usado para delimitar o limite entre o URI de um questionável objeto e um conjunto de palavras usadas para expressar uma consulta nesse objeto. Quando esse formulário é usado, o URI combinado representa o objeto que resulta da consulta aplicada ao objeto original. " (ênfase minha). Assim, é claro que a string de consulta é de fato parte da URI (embora a parte antes da string de consulta é, necessariamente, também um URI válido por si só) ...
Ilmari Karonen

... e esse URI combinado identifica um recurso específico que o cliente pode solicitar enviando esse URI para o servidor. Em qualquer caso, o RFC 2616 (HTTP) simplesmente define um recurso como "Um objeto ou serviço de dados de rede que pode ser identificado por um URI, conforme definido na seção 3.2". e continua dizendo que "No que diz respeito ao HTTP, os Identificadores Uniformes de Recursos são simplesmente cadeias formatadas que identificam - via nome, local ou qualquer outra característica - um recurso".
Ilmari Karonen

@IlmariKaronen você está certo. Confundi HTTP com REST. Ainda não parece certo, porque embora eu não tenho certeza do que você pode fazer com um recurso com URI como / GoalTree / Get versionDate = 2000 aC?
imel96

3

Que tal um 204 sem conteúdo? Isso sugere que sua solicitação foi processada com êxito, mas não está retornando nada. Ainda é um "sucesso", mas permite que você veja se possui resultados apenas com base no código de status.


6
se você ler mais as especificações, "Esta resposta tem como objetivo principal permitir a entrada de ações sem causar uma alteração na exibição do documento ativo do agente do usuário". Portanto, não deve ser usado para solicitações GET.
Imel96

3

Se o URL representar um recurso que nunca existiu, retorne 404 Não encontrado

Se o URL representar um recurso que é uma lista vazia, retorne uma lista vazia e 200 OK.

Exemplo:

{
  total: 0,
  items: []
}

Se o URL representar um recurso que existia, retorne 410 Gone.

Sobre o diálogo de Lego Stormtrooper:

Alien: Computer, please tell me all planets that humans inhabit. GET /planets?inhabitedBy=humans

Computer: 200 OK. { total: 1, items:[{name:'Earth'}] }

Alien: Computer, please tell me about Earth. GET /planets/earth

Computer: 200 OK. {name:'Earth', status: 'Mostly Harmless'}

Alien: Computer, please tell me about all planets humans inhabit, outside the asteroid belt. GET /planets?inhabitedBy=humans&distanceFromSun=lots

Computer: 200 OK. {total:0, items:[] }

Alien: Computer, please destroy Earth. DELETE /planets/earth

Computer: 204 No Content. (or 202 Accepted if it takes some time to destroy Earth)

Alien: Computer, please tell me about Earth. GET /planets/earth

Computer: 410 Gone

Alien: Computer, please tell me all planets that humans inhabit. GET /planets?inhabitedBy=humans

Computer: 200 OK 0 {total: 0, items:[] }

Alien: Victory for the mighty Irken Empire!

1

Pelo que parece, esta é uma API para uso interno . Isso dá a vantagem de usar qualquer esquema que traga mais benefícios , independentemente de ser manual ou não (especificação). Isso não significa inventar completamente seus próprios códigos de status, mas não há problema em 'torcer' as regras um pouco, se for benéfico.

Concordo com a sua posição de que você deve obter um código de status que mostre que algo deu errado. Afinal, é para isso que servem os códigos de status. Além disso, você obtém o benefício de bibliotecas que lançam exceções / etc. no código de status que não seja 200, para que você não precise verificar explicitamente (ou pode escrever seu próprio wrapper que faz isso).

Também concordo com o ponto de vista de Andres F. de que 500 é apropriado, pois a árvore deve existir. Na prática, eu gosto de dividir os erros do servidor em duas categorias. Algo inesperado deu errado e algo que eu posso praticamente verificar deu errado. Isso resulta nos seguintes códigos de status,

  • 200 - Tudo está bem
  • 404 - URL incorreto
  • 409 - Algo deu errado
  • 500 - Ocorreu um erro inesperado no servidor

No seu caso particular, você pode verificar se a árvore existe ou não no lado do servidor e, se não estiver lá, retornar um 409. É um erro esperado (você sabe que isso pode acontecer, pode verificar, etc.) . Se o conflito é apenas minha preferência pessoal, um 5xx também pode ser apropriado desde que você possa se sentar e decidir isso com sua equipe.

A categorização de códigos como esse ajuda a identificar mais rapidamente o tipo de erro, mas pode trazer benefícios além da organização. Geralmente, com erros no site, você não deseja que o cliente obtenha erros inesperados, pois isso pode ser uma preocupação de segurança e revelar vulnerabilidades, e você retorna 500 genéricos "Ocorreu um erro". e registre o erro completo no servidor. Mas se um erro esperado ocorrer como um 409, você sabe que seria seguro mostrar o erro ao cliente e não precisa deixá-lo no escuro sobre o que aconteceu. Esse é apenas um uso prático que posso contar, mas há muitas possibilidades.

Isso é um pouco complicado porque você está postando isso por não conseguir concordar com seus colegas de trabalho, mas parece que vocês estão discutindo mais sobre semântica e quem é politicamente correto. Realmente não importa quem é mais adequado, desde que você possa criar um sistema que mais beneficie a empresa.

Por outro lado, se essa é uma API pública que segue as especificações o mais próximo possível, seria mais importante para evitar confusão entre a comunidade.


0

Tomando uma facada tangencial no seguinte: se um humano estiver usando a API (por meio de uma GUI), eu sugeriria que fizesse o que facilita a vida do usuário final. A inexistência da árvore quando deveria existir é um erro "Inconsistência do modelo de domínio". Um erro do sistema ocorre quando você fica sem memória ou apresenta alguma outra falha sistêmica. Portanto, retornar 5xx é inadequado. Como mencionado por várias pessoas acima, 4xx pode ser apropriado se a própria árvore tiver seu próprio URI, o que não é o caso aqui. Mas aqui está o que 404 diz ao cliente: você pode tentar novamente e novamente até obter algo em troca. Se você retornou 200, poderá retornar diagnósticos suficientes de volta ao usuário ou agente do usuário para que o agente do usuário possa exibir uma medição para que o usuário pare de tentar novamente e apenas contate o suporte. Por outro lado, se esta API for destinada apenas a sistemas,


Tudo o que o 404 realmente diz é "essa coisa não está aqui e eu não sei onde está". 3xx e 5xx estão ok para tentar novamente. Mas 4xx diz: "sua consulta atual foi insuficiente para eu encontrar algo para você. Por favor, vá embora".

Eu gosto da possibilidade de distinguir entre URL NÃO ENCONTRADO e Recurso NÃO ENCONTRADO ... Portanto, o Service Endpoint está em funcionamento 200, no entanto, o recurso solicitado não é ENCONTRADO 404 (Corpo de Resposta).
Lemonade
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.