{"id":1654,"date":"2024-09-30T07:22:00","date_gmt":"2024-09-30T10:22:00","guid":{"rendered":"https:\/\/www.erudio.com.br\/blog\/?p=1654"},"modified":"2024-10-01T16:34:49","modified_gmt":"2024-10-01T19:34:49","slug":"entendendo-o-conceito-de-hateoas","status":"publish","type":"post","link":"https:\/\/www.erudio.com.br\/blog\/entendendo-o-conceito-de-hateoas\/","title":{"rendered":"Entendendo o conceito de HATEOAS"},"content":{"rendered":"\n<h3>Introdu\u00e7\u00e3o<\/h3>\n\n\n\n<p>No universo das APIs <strong>REST<\/strong>, uma das caracter\u00edsticas mais avan\u00e7adas e menos compreendidas \u00e9 o conceito de <strong>HATEOAS<\/strong> (<em>Hypermedia as the Engine of Application State<\/em>). Ao contr\u00e1rio de outros tipos de APIs que exigem uma documenta\u00e7\u00e3o externa ou um contrato pr\u00e9-estabelecido, o <strong>HATEOAS<\/strong> prop\u00f5e um modelo onde as pr\u00f3prias respostas da API guiam o cliente em como navegar entre os recursos. Isso transforma a intera\u00e7\u00e3o com a API em algo din\u00e2mico e adapt\u00e1vel, eliminando a depend\u00eancia de defini\u00e7\u00f5es externas e oferecendo uma flexibilidade consider\u00e1vel aos desenvolvedores de aplica\u00e7\u00f5es cliente. Neste artigo, vamos explorar em profundidade o que \u00e9 <strong>HATEOAS<\/strong>, como ele se diferencia de outros padr\u00f5es arquiteturais, e como ele pode ser implementado para maximizar a maturidade de uma API <strong>REST<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/www.erudio.com.br\/blog\/wp-content\/uploads\/2024\/09\/1700647879006-1024x445.png\" alt=\"\" class=\"wp-image-1658\" width=\"512\" height=\"223\" srcset=\"https:\/\/www.erudio.com.br\/blog\/wp-content\/uploads\/2024\/09\/1700647879006-1024x445.png 1024w, https:\/\/www.erudio.com.br\/blog\/wp-content\/uploads\/2024\/09\/1700647879006-300x130.png 300w, https:\/\/www.erudio.com.br\/blog\/wp-content\/uploads\/2024\/09\/1700647879006-768x333.png 768w, https:\/\/www.erudio.com.br\/blog\/wp-content\/uploads\/2024\/09\/1700647879006.png 1382w\" sizes=\"(max-width: 512px) 100vw, 512px\" \/><\/figure>\n\n\n\n<h3>Explorando HATEOAS: O N\u00edvel Mais Avan\u00e7ado de Maturidade REST<\/h3>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>HATEOAS<\/strong> (<em>Hypermedia as the Engine of Application State<\/em>) \u00e9 uma <strong>constraint<\/strong> arquitetural dentro do contexto de aplica\u00e7\u00f5es <strong>REST<\/strong>. Trata-se de uma caracter\u00edstica que permite que uma <strong>API HATEOAS<\/strong> forne\u00e7a informa\u00e7\u00f5es que ajudam os clientes a navegar dinamicamente entre seus <strong>endpoints<\/strong>. Isso ocorre porque as respostas das APIs <strong>HATEOAS<\/strong> incluem <strong>links<\/strong> que apontam para outros recursos relacionados, o que diferencia este padr\u00e3o de outras abordagens como os sistemas baseados em <strong>SOA<\/strong> (<em>Service-Oriented Architecture<\/em>) e em interfaces definidas por <strong>WSDL<\/strong> (<strong>W<\/strong>eb <strong>S<\/strong>ervices <strong>D<\/strong>escription <strong>L<\/strong>anguage). Nestes \u00faltimos, servidores e clientes geralmente precisam seguir uma especifica\u00e7\u00e3o est\u00e1tica que pode estar hospedada em algum local externo \u00e0 API ou mesmo distribu\u00edda via outros meios, como por e-mail ou por <strong>websites<\/strong>.<\/p>\n\n\n\n<p>Por outro lado, o uso de <strong>HATEOAS<\/strong> elimina a necessidade de uma especifica\u00e7\u00e3o formal compartilhada previamente entre servidor e cliente. Isso acontece porque as informa\u00e7\u00f5es necess\u00e1rias para navegar pela API s\u00e3o fornecidas diretamente nas respostas, permitindo uma intera\u00e7\u00e3o mais fluida e adapt\u00e1vel \u00e0s mudan\u00e7as na interface da API.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>Nota: A pron\u00fancia de <strong>HATEOAS<\/strong> varia bastante entre desenvolvedores. Algumas pessoas pronunciam algo parecido com \u201criteos\u201d, enquanto outras utilizam \u201creitos\u201d ou ainda \u201creid\u00f4s\u201d. Alternativamente, o termo pode ser referido como um <strong>hypermedia-driven system<\/strong> (<em>sistema dirigido por hiperm\u00eddia<\/em>).<\/p>\n<\/blockquote>\n\n\n\n<h3>Exemplos<\/h3>\n\n\n\n<p>Vamos ilustrar o conceito com um exemplo simples. A seguir, temos uma classe <strong>Cliente<\/strong> escrita em <strong>Java<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>class Cliente {\n    String nome;\n}\n<\/code><\/pre>\n\n\n\n<p>Em uma representa\u00e7\u00e3o <strong>JSON<\/strong> tradicional, o objeto gerado a partir dessa classe seria algo como:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>{\n    \"nome\" : \"Leandro\"\n}\n<\/code><\/pre>\n\n\n\n<p>Os dados do <strong>Cliente<\/strong> est\u00e3o presentes, mas sem quaisquer informa\u00e7\u00f5es adicionais que permitam entender como esse recurso se conecta a outros. Agora, vamos ver como seria uma representa\u00e7\u00e3o <strong>HATEOAS<\/strong> do mesmo objeto:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>{\n   \"nome\":\"Leandro\",\n   \"links\":[\n      {\n         \"rel\":\"self\",\n         \"href\":\"http:\/\/localhost:8080\/Cliente\/1\"\n      }\n   ]\n}\n<\/code><\/pre>\n\n\n\n<p>Aqui, al\u00e9m de conter o nome da pessoa, a resposta tamb\u00e9m inclui um <strong>link<\/strong> para o recurso correspondente. Esse <strong>link<\/strong> serve como um ponto de navega\u00e7\u00e3o para outros dados associados ao cliente. A propriedade <strong>rel<\/strong> indica o tipo de relacionamento, que neste caso \u00e9 <strong>self<\/strong>, ou seja, o <strong>link<\/strong> aponta para o pr\u00f3prio recurso. O atributo <strong>href<\/strong> fornece a <strong>URL<\/strong> completa do recurso, permitindo que o cliente acesse diretamente a informa\u00e7\u00e3o relacionada.<\/p>\n\n\n\n<p>\u00c9 importante destacar que sistemas mais complexos podem definir m\u00faltiplos tipos de relacionamentos. Por exemplo, uma ordem de compra poderia ter uma rela\u00e7\u00e3o com um cliente, utilizando algo como <code>\"rel\": \"Cliente\"<\/code> para indicar a associa\u00e7\u00e3o entre a ordem e o cliente.<\/p>\n\n\n\n<p><strong>HATEOAS<\/strong> n\u00e3o imp\u00f5e um formato espec\u00edfico para as respostas. Embora os exemplos aqui sejam em <strong>JSON<\/strong>, \u00e9 perfeitamente poss\u00edvel utilizar outros formatos como <strong>XML<\/strong>. O foco de <strong>HATEOAS<\/strong> \u00e9 prover <strong>links<\/strong> que permitem a navega\u00e7\u00e3o entre os recursos expostos pela API, independentemente do formato de serializa\u00e7\u00e3o dos dados.<\/p>\n\n\n\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_java\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0  AWS com Spring Boot 3, Java e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/07-rest-spring-java.png\">\n<\/a>\n\n\n\n<h3>Complexidade e Dinamismo<\/h3>\n\n\n\n<p>Embora os exemplos acima sejam simples, as APIs <strong>HATEOAS<\/strong> podem construir rela\u00e7\u00f5es bastante complexas. Essa flexibilidade \u00e9 extremamente \u00fatil para os desenvolvedores, uma vez que eles podem explorar e consumir os recursos da API sem precisar consultar uma documenta\u00e7\u00e3o externa ou seguir uma especifica\u00e7\u00e3o previamente conhecida. A API se torna autoexplicativa, fornecendo as informa\u00e7\u00f5es de navega\u00e7\u00e3o diretamente nas respostas.<\/p>\n\n\n\n<p>Vejamos um exemplo mais detalhado de uma resposta <strong>HATEOAS<\/strong>, desta vez contendo uma lista de produtos:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>{\n   \"conteudo\":[\n      {\n         \"preco\":499.00,\n         \"descricao\":\"HD Seagate 2TB\",\n         \"nome\":\"HD S2TB\",\n         \"links\":[\n            {\n               \"rel\":\"self\",\n               \"href\":\"http:\/\/localhost:8080\/produto\/1\"\n            }\n         ],\n         \"atributos\":{\n            \"conector\":\"SATA\"\n         }\n      },\n      {\n         \"preco\":49.00,\n         \"descricao\":\"Mouse \u00d3ptico Dell\",\n         \"nome\":\" Mouse\",\n         \"links\":[\n            {\n               \"rel\":\"self\",\n               \"href\":\"http:\/\/localhost:8080\/produto\/3\"\n            }\n         ],\n         \"atributos\":{\n            \"conector\":\"wireless\"\n         }\n      }\n   ],\n   \"links\":[\n      {\n         \"rel\":\"produto.consulta\",\n         \"href\":\"http:\/\/localhost:8080\/produto\/consulta\"\n      }\n   ]\n}\n<\/code><\/pre>\n\n\n\n<p>Aqui, al\u00e9m das informa\u00e7\u00f5es detalhadas sobre os produtos, como <strong>pre\u00e7o<\/strong>, <strong>descri\u00e7\u00e3o<\/strong> e <strong>atributos<\/strong>, a resposta cont\u00e9m <strong>links<\/strong> para cada recurso, permitindo que o cliente acesse as informa\u00e7\u00f5es completas de cada item de forma direta. Esse modelo de navega\u00e7\u00e3o, suportado pelo <strong>HATEOAS<\/strong>, facilita a intera\u00e7\u00e3o com a API de maneira din\u00e2mica, sem exigir um conhecimento pr\u00e9vio dos <strong>endpoints<\/strong> dispon\u00edveis.<\/p>\n\n\n\n<h3>Maturidade do REST e HATEOAS<\/h3>\n\n\n\n<p>Segundo o <strong>Richardson Maturity Model<\/strong>, <strong>HATEOAS<\/strong> representa o n\u00edvel mais alto de maturidade em uma API <strong>REST<\/strong>. Isso implica que, al\u00e9m de adotar os princ\u00edpios fundamentais do <strong>REST<\/strong>, como o uso de <strong>verbos HTTP<\/strong> (<em>GET<\/em>, <em>POST<\/em>, <em>PUT<\/em>, <em>DELETE<\/em>), uma API madura baseada em <strong>HATEOAS<\/strong> tamb\u00e9m deve fornecer <strong>links<\/strong> adequados para que o cliente possa navegar pelos recursos.<\/p>\n\n\n\n<p>Com isso, o cliente n\u00e3o s\u00f3 acessa os dados, mas tamb\u00e9m \u00e9 guiado pela API a encontrar outros recursos relevantes, o que cria uma interface verdadeiramente <strong>hypermedia-driven<\/strong>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p><strong>Importante<\/strong>: Embora tenhamos ilustrado os exemplos usando <strong>JSON<\/strong>, o suporte a <strong>HATEOAS<\/strong> pode ser implementado em uma variedade de formatos de resposta, incluindo <strong>XML<\/strong>. O formato utilizado n\u00e3o \u00e9 o aspecto central; o que importa \u00e9 a capacidade de fornecer <strong>links<\/strong> naveg\u00e1veis que descrevem as rela\u00e7\u00f5es entre os recursos.<\/p>\n<\/blockquote>\n\n\n\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_asp_net\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0 Azure com ASP.NET Core 5 e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/01-rest-asp.png\">\n<\/a>\n\n\n\n<h3>Conclus\u00e3o<\/h3>\n\n\n\n<p>O conceito de <strong>HATEOAS<\/strong> n\u00e3o apenas eleva a maturidade de uma API <strong>REST<\/strong>, como tamb\u00e9m simplifica a intera\u00e7\u00e3o dos clientes com os recursos, promovendo uma navega\u00e7\u00e3o din\u00e2mica e autoexplicativa. Ao adotar essa pr\u00e1tica, desenvolvedores podem construir APIs mais flex\u00edveis e escal\u00e1veis, nas quais a necessidade de consultar documenta\u00e7\u00e3o externa \u00e9 reduzida ao m\u00ednimo. Aplicando <strong>HATEOAS<\/strong> corretamente, a API se torna mais intuitiva, uma vez que as pr\u00f3prias respostas guiam o cliente sobre os pr\u00f3ximos passos a seguir. No pr\u00f3ximo artigo, entraremos em uma abordagem pr\u00e1tica com <strong>Spring Boot<\/strong>, onde veremos como implementar essa poderosa t\u00e9cnica em projetos reais.<\/p>\n\n\n\n<h2>Treinamentos relacionados com essa postagem<\/h2>\n\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_java\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0  AWS com Spring Boot 3, Java e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/07-rest-spring-java.png\">\n<\/a>\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_tests_java\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Java Unit Testing com Spring Boot 3, TDD, Junit 5 e Mockito\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/24-tests_java.png\">\n<\/a>\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_ci_cd_java_aws\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Java Continuous Integration e Continuous Delivery com AWS e Github Actions\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/27_CICD_JavaAWS.png\">\n<\/a>\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_ci_cd_java_azure\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Java Continuous Integration e Continuous Delivery com Microsoft Azure e Github Actions\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/28_CICD_JavaAzure.png\">\n<\/a>\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_asp_net\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0 Azure com ASP.NET Core 5 e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/01-rest-asp.png\">\n<\/a>\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_kotlin\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0 AWS com Spring Boot 3, Kotlin e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/18-rest-spring-kotlin.png\">\n<\/a>\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_microservices_java\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Microservices do 0 com Spring Cloud, Spring Boot e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/14-microservices-java.png\">\n<\/a>\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_microservices-dotnet\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Arquitetura de Microsservi\u00e7os do 0 com ASP.NET, .NET 6 e C#\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/15-microservices-dotnet.png\">\n<\/a>\n<a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_ms_kotlin\" target=\"_blank\" rel=\"noopener\">\n  <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Microsservi\u00e7os do 0 com Spring Cloud, Kotlin e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/22-ms-kotlin.png\">\n<\/a>\n","protected":false},"excerpt":{"rendered":"<p>Introdu\u00e7\u00e3o No universo das APIs REST, uma das caracter\u00edsticas mais avan\u00e7adas e menos compreendidas \u00e9 o conceito de HATEOAS (Hypermedia as the Engine of Application State). Ao contr\u00e1rio de outros tipos de APIs que exigem uma documenta\u00e7\u00e3o externa ou um contrato pr\u00e9-estabelecido, o HATEOAS prop\u00f5e um modelo onde as pr\u00f3prias respostas da API guiam o [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1660,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[11,305,311,40,96],"tags":[132,166,312,221,313],"_links":{"self":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/1654"}],"collection":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/comments?post=1654"}],"version-history":[{"count":4,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/1654\/revisions"}],"predecessor-version":[{"id":1663,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/1654\/revisions\/1663"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/media\/1660"}],"wp:attachment":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/media?parent=1654"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/categories?post=1654"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/tags?post=1654"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}