APIs robustas e bem modeladas simplificam a construção de aplicações clientes, reduzindo o acoplamento e a necessidade delas implementarem “inteligência do negócio”.
[tweet]Em APIs REST, a redução de acoplamento e da necessidade de implementar “inteligência do negócio” nas aplicações clientes é obtida pela adoção de HATEOAS.[/tweet]
O que é HATEOAS?
Hypermedia as the Engine of Application State, ou HATEOAS, é uma “maneira” de implementar APIs REST utilizando hipermídia para indicar que ações ou navegações estão disponíveis para um determinado recurso.
As ações e a navegação são derivadas do estado do recurso e, eventualmente, da própria API. Elas são disponibilizadas para o cliente através de uma coleção de links.
{ “custormerId”: 1, “firstName”: “John”, “lastName”: “Doe”, ... links: [] }
Não há uma definição universalmente aceita sobre onde esta coleção de links deve ser fornecida. Há quem defenda a inclusão na representação do recurso. Outros, defendem a utilização dos cabeçalhos da “response HTTP”.
Quanto aos dados necessários em cada link, há uma RFC (5598).
Que links deveriam ser fornecidos?
A coleção de links em uma implementação HATEOAS deveria ser suficiente para indicar que ações são suportas para um determinado recurso e, também, navegação para recursos relacionados (incluindo self).
O link para self
O primeiro link da coleção deveria ser uma referência para o próprio objeto.
{ “custormerId”: 1, “firstName”: “John”, “lastName”: “Doe”, ... links: [{ “rel”: “self”, “href”: “http://mydomain/customers/1” ] }] }
Dessa forma, caso a representação do recurso “passeie” pela aplicação cliente, ou, caso ela, eventualmente, seja persistida ou compartilhada com outros contextos, em qualquer momento, seria possível determinar sua origem sem “inferências no código”.
Na eventualidade de haver mudanças nas rotas da API, endereços antigos devem redirecionar para o novo endereço.
Links para as ações suportadas pelo recurso
Imagine-se concebendo uma interface para o usuário. Nela, deve ser possível alterar os dados de um recurso ou solicitar sua exclusão. Eventualmente, alguns recursos (um pedido, por exemplo) não podem ser alterados sob certas condições. Ou ainda, não podem ser excluídos. Como e onde a “lógica” para determinar as ações possíveis deve ser implementada?
{ “custormerId”: 1, “firstName”: “John”, “lastName”: “Doe”, ... links: [{ “rel”: “self”, “href”: “http://mydomain/customers/1” ] },{ “rel”: “update”, “href”: “http://mydomain/customers/1” ] },{ “rel”: “delete”, “href”: “http://mydomain/customers/1” ] }] }
Fornecer a lista de ações possíveis para um recurso na coleção de links permite que essa lógica seja implementada totalmente no serviço e simplifica muito a implementação da aplicação cliente. O botão “excluir”, por exemplo, estaria disponível apenas se o link correspondente estivesse na coleção.
Outra vantagem de retornar a lista de links com as ações disponíveis é que a lógica pode mudar no servidor, incluindo os endereços, sem alteração alguma no código da aplicação cliente.
Links para navegação
Eventualmente, um recurso retornado pela API possuirá outros recursos relacionados. Por exemplo, em uma aplicação empresarial, um “cliente” possuirá uma coleção de “pedidos” que realizou.
{ “custormerId”: 1, “firstName”: “John”, “lastName”: “Doe”, ... links: [{ “rel”: “self”, “href”: “http://mydomain/customers/1” ] },{ “rel”: “update”, “href”: “http://mydomain/customers/1” ] },{ “rel”: “delete”, “href”: “http://mydomain/customers/1” ] },{ “rel”: “orders”, “href”: “http://mydomain/customers/1/orders” ] }] }
A presença desses links evita que a aplicação cliente precise fazer “inferências” sobre como “chegar” em recursos relacionados, diminuindo acoplamento. Essa ação autoriza, por exemplo, a mudança na estratégia de rotas sem afetar a aplicação cliente.
{ “custormerId”: 1, “firstName”: “John”, “lastName”: “Doe”, ... links: [ ..., { “rel”: “orders”, “href”: “http://mydomain/orders?customerId=1” ] }] }
HATEOAS não substitui documentação
Pelos exemplos destacados é possível verificar que os links não possuem todas as informações necessárias para explorar plenamente a API. Não há indicação, por exemplo, de qual verbo HTTP deve ser utilizado para link embora fique “implícito” que self deve ser solicitado com um GET e que update deva ser solicitado com um PUT. Também não há indicação do formato do recurso (quais informações vão estar presentes e de que forma elas serão expostas).
Documentação complementar será necessária, tanto para descrever os recursos como para indicar o significado de cada rel.
Deveria implementar HATEOAS em meus serviços REST?
Não necessariamente. Sem dúvidas, HATEOAS diminui o acoplamento e a necessidade de implementar lógica de negócio na aplicação cliente. Mas, há incontáveis exemplos de APIs implementadas sem este conceito.
Também é importante destacar que HATEOAS impõe um overhead nas representações de recursos que, dependendo do volume e restrições de banda podem ser significativos.
Como deve ser feita a implementação?
A implementação de HATEOAS varia conforme a tecnologia que está sendo utilizada no backend. De qualquer forma, é importante que seja destacado que praticamente todas as tecnologias possuem pacotes e extensões que facilitam a implementação.