HATEOAS é uma restrição que faz parte da arquitetura de aplicações REST, cujo objetivo é ajudar os clientes a consumirem o serviço sem a necessidade de conhecimento prévio profundo da API.
O acrônimo HATEOAS vem de Hypermedia As the Engine Of Application State e o termo “hypermedia” no seu nome já dá uma ideia de como este componente funciona em uma aplicação RESTful. Ao ser implementado, a API passa a fornecer links que indicarão aos clientes como navegar através dos seus recursos.
Com isso, o cliente não precisa ter um conhecimento profundo da API, basta conhecer a URL de inicial e partir dos links fornecidos poderá acessar todos os recursos de forma circular, se guiando através das requisições realizadas.
Um exemplo clássico para explicar o HATEOAS, é o Hypertext, do HTML. Quando se necessita obter uma informação de um site, como um curso aqui da Treinaweb, o usuário pode acessar a página inicial (treinaweb.com.br), nela clicar em Cursos e depois no curso desejado. No fim, o usuário terá acessado uma URL como treinaweb.com.br/curso/java-fundamentos-de-jax-ws-e-jax-rs, onde conseguirá visualizar o curso. Não foi necessário que o usuário soubesse de antemão a URL desejada, pois é importante que o site, através de links, guie-o e auxilie-o na busca do recurso desejado. Com o HATEOAS uma API REST segue o mesmo padrão.
Um exemplo simples do HATEOAS
Por exemplo, ao acessar uma API de cursos, na URL api.treinaweb.com.br/cursos, o cliente terá o seguinte resultado:
{
"cursos": [
{
"id": 1,
"nome": "C# (C Sharp)",
"aulas": [
{
"id": 1,
"titulo": "Título da aula 3"
},
{
"id": 2,
"titulo": "Título da aula 3"
},
{
"id": 3,
"titulo": "Título da aula 3"
},
]
},
{
"id": 2,
"nome": "PHP",
"aulas": [
{
"id": 1,
"titulo": "Título da aula 3"
},
{
"id": 2,
"titulo": "Título da aula 3"
},
{
"id": 3,
"titulo": "Título da aula 3"
},
]
},
{
"id": 3,
"nome": "Java",
"aulas": [
{
"id": 1,
"titulo": "Título da aula 3"
},
{
"id": 2,
"titulo": "Título da aula 3"
},
{
"id": 3,
"titulo": "Título da aula 3"
},
]
},
]
}
Se esta API implementasse o padrão HATEOAS, a resposta obtida poderia ser outra. No lugar de listar as aulas, cada curso teria um recurso próprio que retornaria suas aulas. Evitando assim que elas fiquem expostas do corpo da requisição. Algo como o exemplo abaixo:
{
"cursos": [
{
"id": 1,
"nome": "C# (C Sharp)",
"aulas": "api.treinaweb.com.br/cursos/1/aulas"
},
{
"id": 2,
"nome": "PHP",
"aulas": "api.treinaweb.com.br/cursos/2/aulas"
},
{
"id": 3,
"nome": "Java",
"aulas": "api.treinaweb.com.br/cursos/3/aulas"
},
]
}
Desta forma, se o cliente desejasse obter as aulas do curso de PHP, em seguida acessaria a URL api.treinaweb.com.br/cursos/2/aulas. Note que nem é necessário montar a URL, a API já fornece o caminho correto completo.
Curso Java - Collections - Parte 2
Conhecer o cursoEspecificação do HATEOAS
No exemplo anterior, o HATEOAS foi exemplificado como uma URL na resposta da API, entretanto, na prática, recomenda-se que a implementação da HATEOAS siga um dos padrões abaixo:
RFC 5988
A especificação RFC 5988 da IETF define como links devem ser implementados. De acordo com ela, cada link deve ter as informações:
-
URI: Cada link deve conter uma URI, representada no atributo
href
; -
Tipo de relação: Descreve como a URI se relaciona com o recurso atual, representado pelo atributo
rel
, devidado de relationship; -
Atributos para URI: Para descrever melhor a URI podem ser adicionados atributos como:
hreflang
,media
,title
etype
.
JSON Hypermedia API Language (HAL)
JSON HAL é uma especificação, proposta por Mike Kelly, ainda não aprovada, mas já comumente utilizada, que define dois MIME Types:
application/hal+xml
application/hal+json
Que ao serem enviados na solicitação, a API REST deve retornar uma propriedade links, contendo as informações:
-
URI: A URI do recurso, representada pelo atributo
href
; -
Tipo de relação: Descreve como a URI se relaciona com o recurso atual, representado pelo atributo
rel
; - Tipo: Descreve o tipo de conteúdo obtido ou do tipo de verbo que deve ser utilizado para acessar a URI. Representado pelo atributo type.
Desta forma, na prática, uma API REST que implemente HATEOAS retornar uma resposta como a abaixo:
{
"cursos": [
{
"id": 1,
"nome": "C# (C Sharp)",
"links": [
{
"type": "GET",
"rel": "self",
"uri": "api.treinaweb.com.br/cursos/1"
},
{
"type": "GET",
"rel": "curso_aulas",
"uri": "api.treinaweb.com.br/cursos/1/aulas"
},
{
"type": "PUT",
"rel": "curso_atualizacao",
"uri": "api.treinaweb.com.br/cursos/1"
},
{
"type": "DELETE",
"rel": "curso_exclusao",
"uri": "api.treinaweb.com.br/cursos/1"
}
]
},
{
"id": 2,
"nome": "PHP",
"links": [
{
"type": "GET",
"rel": "self",
"uri": "api.treinaweb.com.br/cursos/2"
},
{
"type": "GET",
"rel": "curso_aulas",
"uri": "api.treinaweb.com.br/cursos/2/aulas"
},
{
"type": "PUT",
"rel": "curso_atualizacao",
"uri": "api.treinaweb.com.br/cursos/2"
},
{
"type": "DELETE",
"rel": "curso_exclusao",
"uri": "api.treinaweb.com.br/cursos/2"
}
]
},
{
"id": 3,
"nome": "Java",
"links": [
{
"type": "GET",
"rel": "self",
"uri": "api.treinaweb.com.br/cursos/3"
},
{
"type": "GET",
"rel": "curso_aulas",
"uri": "api.treinaweb.com.br/cursos/3/aulas"
},
{
"type": "PUT",
"rel": "curso_atualizacao",
"uri": "api.treinaweb.com.br/cursos/3"
},
{
"type": "DELETE",
"rel": "curso_exclusao",
"uri": "api.treinaweb.com.br/cursos/3"
}
]
}
]
}
Vantagens do HATEOAS
Uma das principais vantagens do HATEOAS é permitir representar o estado de um recurso ou as limitações de um usuário sem a necessidade da implementação de outras lógicas no cliente.
Por exemplo, imagine uma API de um banco. Ao consultar o saldo do usuário, caso este tenha saldo em conta, pode ser retornado os seguintes dados:
{
"conta": {
"numero": 1234,
"saldo": 5120.09,
"links":
[
{
"type": "GET",
"rel": "self",
"uri": "api.banco.com.br/usuario/1/conta/1234"
},
{
"type": "PUT",
"rel": "conta_saque",
"uri": "api.banco.com.br/usuario/1/conta/1234/saque"
},
{
"type": "PUT",
"rel": "conta_deposito",
"uri": "api.banco.com.br/usuario/1/conta/1234/deposito"
}
]
}
}
Caso não tenha saldo, o resultado pode mudar para:
{
"conta": {
"numero": 1234,
"saldo": -20.14,
"links":
[
{
"type": "GET",
"rel": "self",
"uri": "api.banco.com.br/usuario/1/conta/1234"
},
{
"type": "PUT",
"rel": "conta_deposito",
"uri": "api.banco.com.br/usuario/1/conta/1234/deposito"
}
]
}
}
Desta forma, o cliente não precisa se preocupar com o estado do usuário. Ele saberá que os ações disponíveis serão as retornadas no atributo links
.
Outra vantagem é a prevenção do chamado “hardcoding”, quando informações são inseridas diretamente no código da aplicação. Em todos os nossos exemplos vimos que o cliente precisa conhecer apenas a URL base da API, pois esta já irá retornar as demais URLs disponíveis.
Por este comportamento que o HATEOAS geralmente é aplicado em aplicações de proposito mais geral, que são criadas para sobreviverem por um longo período. Onde alterações na API não irão impactar muito nos clientes.
Curso C# (C Sharp) - APIs REST com ASP.NET Web API
Conhecer o cursoConclusão
De acordo com o modelo de maturidade de Richardson, o HATEOAS é considerado o último nível de uma API RESTful. Desta forma, caso esteja procurando definir uma API que siga o padrão RESTful, o HATEOAS deve ser implementado nela.
Mas mesmo que não esteja seguindo o padrão RESTful a risca, é fato que o componente HATEOAS facilita e muito a manutenção de uma API e a sua integração com outras aplicações. Então, sempre que possível procure implementá-la nas APIs que desenvolver.