{"id":831,"date":"2016-06-26T06:00:40","date_gmt":"2016-06-26T09:00:40","guid":{"rendered":"https:\/\/www.semeru.com.br\/blog\/?p=831"},"modified":"2022-12-21T11:32:49","modified_gmt":"2022-12-21T14:32:49","slug":"aplicacoes-restfull-hateoas-com-springboot","status":"publish","type":"post","link":"https:\/\/www.semeru.com.br\/blog\/aplicacoes-restfull-hateoas-com-springboot\/","title":{"rendered":"Aplica\u00e7\u00f5es RESTful HATEOAS com SpringBoot"},"content":{"rendered":"<p>&nbsp;<\/p>\n<p>O <strong>HATEOAS<\/strong>, \u00e9 uma das principais constraints arquiteturais do <strong>REST<\/strong> e possibilita a navega\u00e7\u00e3o entre recursos, que s\u00e3o representa\u00e7\u00f5es dos modelos de neg\u00f3cio da aplica\u00e7\u00e3o. Esse post \u00e9 bem m\u00e3o na massa e se quiser aprofundar um pouco mais em conceitos te\u00f3ricos de <strong>HATEOAS<\/strong> confira o nosso post <a href=\"https:\/\/www.semeru.com.br\/blog\/entendendo_hateoas\/\" target=\"_blank\" rel=\"noopener\">Entendendo <strong>HATEOAS<\/strong><\/a>. Vamos tomar como base a aplica\u00e7\u00e3o desenvolvida no nosso outro post <a href=\"https:\/\/www.semeru.com.br\/blog\/documentando-aplicacoes-restfull-com-springboot-e-swagger\/\" target=\"_blank\" rel=\"noopener\">Documentando aplica\u00e7\u00f5es REST com SpringBoot e Swagger<\/a>. Para come\u00e7ar voc\u00ea pode <a href=\"https:\/\/github.com\/leandrocgsi\/simple-rest-example-swagger\/archive\/master.zip\">baixar o c\u00f3digo deste post aqui<\/a> e descompactar o arquivo zip e importar na sua IDE preferida ou clonar usando Git:<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\ngit clone https:\/\/github.com\/leandrocgsi\/simple-rest-example-swagger.git\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Primeiro altere o <strong><em>pom.xml<\/em><\/strong> adicionando os trechos destacados por coment\u00e1rios abaixo.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;project xmlns=&quot;http:\/\/maven.apache.org\/POM\/4.0.0&quot; xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot; xsi:schemalocation=&quot;http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd&quot;&gt;\n    &lt;modelversion&gt;4.0.0&lt;\/modelversion&gt;\n\n    &lt;groupid&gt;br.com.erudio&lt;\/groupid&gt;\n    &lt;artifactid&gt;simple-rest-example-hateoas&lt;\/artifactid&gt;\n    &lt;version&gt;0.0.1-SNAPSHOT&lt;\/version&gt;\n\n    &lt;parent&gt;\n        &lt;groupid&gt;org.springframework.boot&lt;\/groupid&gt;\n        &lt;artifactid&gt;spring-boot-starter-parent&lt;\/artifactid&gt;\n        &lt;version&gt;1.3.3.RELEASE&lt;\/version&gt;\n    &lt;\/parent&gt;\n\n    &lt;dependencies&gt;\n\n        &lt;dependency&gt;\n            &lt;groupid&gt;org.springframework.boot&lt;\/groupid&gt;\n            &lt;artifactid&gt;spring-boot-starter-web&lt;\/artifactid&gt;\n        &lt;\/dependency&gt;\n        &lt;dependency&gt;\n            &lt;groupid&gt;org.springframework.boot&lt;\/groupid&gt;\n            &lt;artifactid&gt;spring-boot-starter-actuator&lt;\/artifactid&gt;\n        &lt;\/dependency&gt;\n\n        &lt;!-- Adicione a dependencia de HATEOAS--&gt;\n        &lt;dependency&gt;\n            &lt;groupid&gt;org.springframework.boot&lt;\/groupid&gt;\n            &lt;artifactid&gt;spring-boot-starter-hateoas&lt;\/artifactid&gt;\n        &lt;\/dependency&gt;\n\n        &lt;dependency&gt;\n            &lt;groupid&gt;com.mangofactory&lt;\/groupid&gt;\n            &lt;artifactid&gt;swagger-springmvc&lt;\/artifactid&gt;\n            &lt;version&gt;1.0.0&lt;\/version&gt;\n        &lt;\/dependency&gt;\n        &lt;dependency&gt;\n            &lt;groupid&gt;org.ajar&lt;\/groupid&gt;\n            &lt;artifactid&gt;swagger-spring-mvc-ui&lt;\/artifactid&gt;\n            &lt;version&gt;0.4&lt;\/version&gt;\n        &lt;\/dependency&gt;\n        &lt;dependency&gt;\n            &lt;groupid&gt;org.apache.tomcat.embed&lt;\/groupid&gt;\n            &lt;artifactid&gt;tomcat-embed-jasper&lt;\/artifactid&gt;\n            &lt;scope&gt;provided&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n\n        &lt;!-- Adicione as dependencias de teste --&gt;\n        &lt;dependency&gt;\n            &lt;groupid&gt;org.springframework.boot&lt;\/groupid&gt;\n            &lt;artifactid&gt;spring-boot-starter-test&lt;\/artifactid&gt;\n            &lt;scope&gt;test&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n        &lt;dependency&gt;\n            &lt;groupid&gt;com.jayway.jsonpath&lt;\/groupid&gt;\n            &lt;artifactid&gt;json-path&lt;\/artifactid&gt;\n            &lt;scope&gt;test&lt;\/scope&gt;\n        &lt;\/dependency&gt;        \n\n    &lt;\/dependencies&gt;\n\n    &lt;properties&gt;\n        &lt;java.version&gt;1.8&lt;\/java.version&gt;\n    &lt;\/properties&gt;\n\n    &lt;build&gt;\n        &lt;plugins&gt;\n            &lt;plugin&gt;\n                &lt;groupid&gt;org.springframework.boot&lt;\/groupid&gt;\n                &lt;artifactid&gt;spring-boot-maven-plugin&lt;\/artifactid&gt;\n            &lt;\/plugin&gt;\n        &lt;\/plugins&gt;\n    &lt;\/build&gt;\n\n    &lt;repositories&gt;\n        &lt;repository&gt;\n            &lt;id&gt;spring-releases&lt;\/id&gt;\n            &lt;url&gt;https:\/\/repo.spring.io\/libs-release&lt;\/url&gt;\n        &lt;\/repository&gt;\n        &lt;repository&gt;\n            &lt;id&gt;jcenter-release&lt;\/id&gt;\n            &lt;name&gt;jcenter&lt;\/name&gt;\n            &lt;url&gt;http:\/\/oss.jfrog.org\/artifactory\/oss-release-local\/&lt;\/url&gt;\n        &lt;\/repository&gt;\n    &lt;\/repositories&gt;\n\n    &lt;pluginrepositories&gt;\n        &lt;pluginrepository&gt;\n            &lt;id&gt;spring-releases&lt;\/id&gt;\n            &lt;url&gt;https:\/\/repo.spring.io\/libs-release&lt;\/url&gt;\n        &lt;\/pluginrepository&gt;\n    &lt;\/pluginrepositories&gt;\n\n&lt;\/project&gt;\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Primeiro vamos alterar a classe <strong>Greeting<\/strong> que agora ira extender <strong>ResourceSupport<\/strong>.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.models;\n\nimport org.springframework.hateoas.ResourceSupport;\n\nimport com.fasterxml.jackson.annotation.JsonCreator;\nimport com.fasterxml.jackson.annotation.JsonProperty;\n\npublic class Greeting extends ResourceSupport {\n\n    private final long idGreeting;\n    private final String content;\n\n    @JsonCreator\n    public Greeting(@JsonProperty(&quot;id&quot;) long id, @JsonProperty(&quot;content&quot;) String content) {\n        this.idGreeting = id;\n        this.content = content;\n    }\n\n    public long getIdGreeting() {\n        return idGreeting;\n    }\n\n    public String getContent() {\n        return content;\n    }\n}\n\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Agora adicione os trechos comentados a classe <strong>GreetingController<\/strong>.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.web.controllers;\n\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.wordnik.swagger.annotations.Api;\nimport com.wordnik.swagger.annotations.ApiOperation;\n\nimport br.com.erudio.models.Greeting;\n\n@Api(value = &quot;greeting&quot;)\n@RestController\n@RequestMapping(&quot;\/greeting&quot;)\npublic class GreetingController {\n\n    private static final String template = &quot;Hello, %s!&quot;;\n    private final AtomicLong counter = new AtomicLong();\n\n\t@ApiOperation(value = &quot;Show Greeting Message&quot; )\n\t@ResponseStatus(HttpStatus.OK)\n    @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)\n    public HttpEntity&lt;greeting&gt; greeting(@RequestParam(value=&quot;name&quot;, defaultValue=&quot;World&quot;) String name) {\n\t\tGreeting greeting = new Greeting(counter.incrementAndGet(), String.format(template, name));\n\n\t\t\/\/ Na pr\u00e1tica essa linha adiciona uma auto refer\u00eancia ao pr\u00f3prio endpoint\n\t\t\/\/ e apenas esse pequeno trecho de c\u00f3digo j\u00e1 \u00e9 o suficiente para que o endpoint\n\t\t\/\/ greeting seja HATEOAS\n\t\tgreeting.add(linkTo(methodOn(GreetingController.class).greeting(name)).withSelfRel());\n\n\t\treturn new ResponseEntity&lt;greeting&gt;(greeting, HttpStatus.OK);\n    }\n}\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Se voc\u00ea iniciar a aplica\u00e7\u00e3o e acessar o endere\u00e7o <em><strong>localhost:8080\/greeting<\/strong><\/em> ver\u00e1 algo similar a imagem abaixo.<\/p>\n<p><a href=\"https:\/\/www.semeru.com.br\/blog\/aplicacoes-restfull-hateoas-com-springboot\/postagem_4_0\/\" rel=\"attachment wp-att-838\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-838\" src=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_0.png\" alt=\"postagem_4_0\" width=\"469\" height=\"412\" srcset=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_0.png 469w, https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_0-300x264.png 300w\" sizes=\"(max-width: 469px) 100vw, 469px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.models;\n\nimport java.io.Serializable;\n\nimport org.springframework.hateoas.ResourceSupport;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\n\n\/\/ Adicione a anota\u00e7\u00e3o @JsonIgnoreProperties\n@JsonIgnoreProperties(ignoreUnknown = true)\n\n\/\/Extenda ResourceSupport\npublic class Person extends ResourceSupport implements Serializable{\n\n    private static final long serialVersionUID = 1L;\n\n\t\/\/ Por padr\u00e3o implementa\u00e7\u00e3o HATEOAS do Spring tem um atributo id\n\t\/\/ como default por isso o ID de nossa entidade deve ser alterado\n    private Long idPerson;\n    private String firstName;\n    private String lastName;\n    private String address;\n\n    public Person() {}\n\n\tpublic Long getIdPerson() {\n        return idPerson;\n    }\n\n    public void setIdPerson(Long id) {\n        this.idPerson = id;\n    }\n\n    public String getFirstName() {\n        return firstName;\n    }\n\n    public void setFirstName(String firstName) {\n        this.firstName = firstName;\n    }\n\n    public String getLastName() {\n        return lastName;\n    }\n\n    public void setLastName(String lastName) {\n        this.lastName = lastName;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n}\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Agora vamos alterar a classe <strong>PersonController<\/strong>:<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.web.controllers;\n\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.wordnik.swagger.annotations.Api;\nimport com.wordnik.swagger.annotations.ApiOperation;\n\nimport br.com.erudio.models.Person;\nimport br.com.erudio.services.PersonService;\n\n@Api(value = &quot;person&quot;)\n@RestController\n@RequestMapping(&quot;\/person\/&quot;)\npublic class PersonController {\n\n    @Autowired\n    private PersonService personService;\n\t@ApiOperation(value = &quot;Find person by ID&quot; )\n    @ResponseStatus(HttpStatus.OK)\n    @RequestMapping(value = &quot;\/{personId}&quot;, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)\n    public Person get(@PathVariable(value = &quot;personId&quot;) String personId){\n        Person person = personService.findById(personId);\n\n\t\t\/\/Adicione uma auto referencia ao m\u00e9todo get do controller passando o ID como par\u00e2metro\n        person.add(linkTo(methodOn(PersonController.class).get(personId)).withSelfRel());\n\t\treturn person;\n    }\n\n    .\n    .\n    .\n\n}\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Note que ao acessar esse recurso com uma ferramenta como o <strong>POSTman<\/strong> teremos uma resultado similar a imagem abaixo.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.semeru.com.br\/blog\/aplicacoes-restfull-hateoas-com-springboot\/postagem_4_1\/\" rel=\"attachment wp-att-832\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-832\" src=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_1.png\" alt=\"postagem_4_1\" width=\"400\" height=\"440\" srcset=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_1.png 400w, https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_1-273x300.png 273w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Agora vamos alterar o <em><strong>findAll<\/strong><\/em>:<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.web.controllers;\n\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.wordnik.swagger.annotations.Api;\nimport com.wordnik.swagger.annotations.ApiOperation;\n\nimport br.com.erudio.models.Person;\nimport br.com.erudio.services.PersonService;\n\n@Api(value = &quot;person&quot;)\n@RestController\n@RequestMapping(&quot;\/person\/&quot;)\npublic class PersonController {\n\n\t@Autowired\n\tprivate PersonService personService;\n\n\t.\n\t.\n\t.\n\n\t@ApiOperation(value = &quot;Find all persons&quot; )\n\t@ResponseStatus(HttpStatus.OK)\n\t@RequestMapping(value = &quot;\/findAll&quot;, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)\n\tpublic List&lt;person&gt; findAll(){\n\t\tList&lt;person&gt; persons = personService.findAll();\n\t\tArrayList&lt;person&gt; personsReturn = new ArrayList&lt;person&gt;();\n\t\tfor (Person person : persons) {\n\t\t\tString idPerson = person.getIdPerson().toString();\n\n\t\t\t\/\/ Adicione uma referencia ao m\u00e9todo get do controller passando o ID como par\u00e2metro\n\t\t\t\/\/ isso \u00e9 feito para todos os elementos da lista\n\t\t\tperson.add(linkTo(methodOn(PersonController.class).get(idPerson)).withSelfRel());\n\t\t\tpersonsReturn.add(person);\n\t\t}\n\t\treturn personsReturn;\n\t}\n\n\t.\n\t.\n\t.\n\n}\n<\/pre>\n<p>&nbsp;<\/p>\n<p>A imagem abaixo nos mostra o resultado dessa mudan\u00e7a. A nossa lista nos tras referencias \u00fanicas para cada um dos recursos.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.semeru.com.br\/blog\/aplicacoes-restfull-hateoas-com-springboot\/postagem_4_2\/\" rel=\"attachment wp-att-833\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-large wp-image-833\" src=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_2.png\" alt=\"postagem_4_2\" width=\"483\" height=\"826\" srcset=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_2.png 483w, https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_2-175x300.png 175w\" sizes=\"(max-width: 483px) 100vw, 483px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Agora vamos adicionar o suporte a <strong>HATEOAS<\/strong> ao verbo <strong>POST<\/strong> da nossa aplica\u00e7\u00e3o.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.web.controllers;\n\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.wordnik.swagger.annotations.Api;\nimport com.wordnik.swagger.annotations.ApiOperation;\n\nimport br.com.erudio.models.Person;\nimport br.com.erudio.services.PersonService;\n\n@Api(value = &quot;person&quot;)\n@RestController\n@RequestMapping(&quot;\/person\/&quot;)\npublic class PersonController {\n\n\t@Autowired\n\tprivate PersonService personService;\n\n\t.\n\t.\n\t.\n\n\t@ApiOperation(value = &quot;Create a new person&quot; )\n\t@ResponseStatus(HttpStatus.OK)\n\t@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)\n\tpublic Person create(@RequestBody Person person){\n\t\tPerson createdPerson = personService.create(person);\n\t\tString idPerson = createdPerson.getIdPerson().toString();\n\n\t\t\/\/ Ap\u00f3s criarmos um novo recurso do tipo Person n\u00f3s recuperamos seu ID e adicionamos\n\t\t\/\/ uma referencia ao m\u00e9todo get do controller passando o ID como par\u00e2metro\n\t\tcreatedPerson.add(linkTo(methodOn(PersonController.class).get(idPerson)).withSelfRel());\n\t\treturn createdPerson;\n\t}\n\n\t.\n\t.\n\t.\n\n}\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Como se pode ver na imagem ap\u00f3s salvar uma nova pessoa a aplica\u00e7\u00e3o retorna um link para que as informa\u00e7\u00f5es da mesma possam ser acessadas.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.semeru.com.br\/blog\/aplicacoes-restfull-hateoas-com-springboot\/postagem_4_3\/\" rel=\"attachment wp-att-834\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-large wp-image-834\" src=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_3.png\" alt=\"postagem_4_3\" width=\"588\" height=\"722\" srcset=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_3.png 588w, https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_3-244x300.png 244w\" sizes=\"(max-width: 588px) 100vw, 588px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Agora vamos modificar o verbo <strong>PUT<\/strong>.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.erudio.web.controllers;\n\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;\nimport static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseStatus;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport com.wordnik.swagger.annotations.Api;\nimport com.wordnik.swagger.annotations.ApiOperation;\n\nimport br.com.erudio.models.Person;\nimport br.com.erudio.services.PersonService;\n\n@Api(value = &quot;person&quot;)\n@RestController\n@RequestMapping(&quot;\/person\/&quot;)\npublic class PersonController {\n\n\t@Autowired\n\tprivate PersonService personService;\n\n\t.\n\t.\n\t.\n\n\t@ApiOperation(value = &quot;Update an existing person&quot;)\n\t@ResponseStatus(HttpStatus.OK)\n\t@RequestMapping(method = RequestMethod.PUT,consumes = MediaType.APPLICATION_JSON_VALUE)\n\tpublic Person update(@RequestBody Person person){\n\t\tPerson updatedPerson = personService.update(person);\n\t\tString idPerson = updatedPerson.getIdPerson().toString();\n\n\t\t\/\/ Ap\u00f3s atualizarmos um recurso n\u00f3s recuperamos seu ID e adicionamos\n\t\t\/\/ uma referencia ao m\u00e9todo get do controller passando o ID como par\u00e2metro\n\t\tupdatedPerson.add(linkTo(methodOn(PersonController.class).get(idPerson)).withSelfRel());\n\t\treturn updatedPerson;\n\t}\n\n\t.\n\t.\n\t.\n\n}\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Da mesma forma que com o verbo <strong>POST<\/strong> ap\u00f3s atualizar uma pessoa a aplica\u00e7\u00e3o retorna um link para que as informa\u00e7\u00f5es da mesma possam ser acessadas.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/www.semeru.com.br\/blog\/aplicacoes-restfull-hateoas-com-springboot\/postagem_4_4\/\" rel=\"attachment wp-att-835\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-large wp-image-835\" src=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_4.png\" alt=\"postagem_4_4\" width=\"588\" height=\"784\" srcset=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_4.png 588w, https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2016\/04\/postagem_4_4-225x300.png 225w\" sizes=\"(max-width: 588px) 100vw, 588px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>Como o verbo <strong>DELETE<\/strong> exclui um recurso n\u00e3o h\u00e1 necessidade de adicionar suporte a <strong>HATEOAS<\/strong> nele. Sendo assim fechamos a nossa implementa\u00e7\u00e3o e podemos dizer que a nossa <strong>API<\/strong> \u00e9 finalmente <strong>RESTful<\/strong>. Assim como nos posts anteriores voc\u00ea pode <a href=\"https:\/\/github.com\/leandrocgsi\/simple-rest-example-hateoas\/archive\/master.zip\">baixar o c\u00f3digo deste post aqui<\/a> e descompactar o arquivo zip e importar na sua IDE preferida ou clonar usando Git:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\ngit clone https:\/\/github.com\/leandrocgsi\/simple-rest-example-hateoas.git\n<\/pre>\n<p>&nbsp;<\/p>\n<p>\u00c9 isso a\u00ed bons estudos e continuem ligados no blog para mais novidades \ud83d\ude09<\/p>\n<p>&nbsp;<\/p>\n<h2>Treinamentos relacionados com este post<\/h2>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_java\" target=\"_blank\" rel=\"noopener\"><\/p>\n<p><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\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_asp_net\" target=\"_blank\" rel=\"noopener\"><\/p>\n<p><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\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\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\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_microservices_java\" target=\"_blank\" rel=\"noopener\"><br \/>\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\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_microservices-dotnet\" target=\"_blank\" rel=\"noopener\"><br \/>\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\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_ms_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\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\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_docker\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Docker do 0 \u00e0 Maestria: Cont\u00eaineres Desmistificados mais 3 B\u00d4NUS\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/09-docker.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_docker_para_aws\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Docker para Amazon AWS Implante Apps Java e .NET com Travis CI\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/10-docker-to-aws.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Kotlin para DEVs Java: Aprenda a Linguagem Padr\u00e3o do Android\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/20-kotlin.png\"><br \/>\n<\/a><\/p>\n<\/person><\/person><\/person><\/person><\/greeting><\/greeting><\/p>\n<div align=\"right\"><div class=\"sharexyWidgetNoindexUniqueClassName\"><div id=\"shr_77453420\"><\/div><\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>&nbsp; O HATEOAS, \u00e9 uma das principais constraints arquiteturais do REST e possibilita a navega\u00e7\u00e3o entre recursos, que s\u00e3o representa\u00e7\u00f5es dos modelos de neg\u00f3cio da aplica\u00e7\u00e3o. Esse post \u00e9 bem m\u00e3o na massa e se quiser aprofundar um pouco mais em conceitos te\u00f3ricos de HATEOAS confira o nosso post Entendendo HATEOAS. Vamos tomar como base [&#8230;]<\/p>\n<div align=\"right\">\n<div class=\"sharexyWidgetNoindexUniqueClassName\">\n<div id=\"shr_77453420\"><\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[117,213,116,63,208,115,211,105],"tags":[205,214,161,209,203,194],"_links":{"self":[{"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/posts\/831"}],"collection":[{"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/comments?post=831"}],"version-history":[{"count":20,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/posts\/831\/revisions"}],"predecessor-version":[{"id":1540,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/posts\/831\/revisions\/1540"}],"wp:attachment":[{"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/media?parent=831"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/categories?post=831"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/tags?post=831"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}