{"id":670,"date":"2015-12-08T13:16:14","date_gmt":"2015-12-08T16:16:14","guid":{"rendered":"https:\/\/www.semeru.com.br\/blog\/?p=670"},"modified":"2022-12-21T10:04:10","modified_gmt":"2022-12-21T13:04:10","slug":"restful-web-services","status":"publish","type":"post","link":"https:\/\/www.semeru.com.br\/blog\/restful-web-services\/","title":{"rendered":"RESTful Web Services"},"content":{"rendered":"<p>Dando seq\u00fc\u00eancia a s\u00e9rie de postagens sobre Web-services neste post, discutiremos sobre a JAX-RS 2.0 a especifica\u00e7\u00e3o para servi\u00e7os baseados em <strong>RESTful<\/strong>. No mundo <strong>REST<\/strong>, voc\u00ea pode acessar tudo como um recurso e eles possuem um identificador \u00fanico a <strong>URI(Uniform Resource Identifier)<\/strong>. Um servidor <strong>REST<\/strong> e seus clientes interagem usando o protocolo <strong>HTTP<\/strong> e seus quatro verbos mais conhecidos que s\u00e3o:<\/p>\n<p><strong>POST &#8211; CREATE\/para inserir recurso<\/strong><\/p>\n<p>O verbo <strong>HTTP POST <\/strong>\u00e9 mais freq\u00fcentemente usado para criar novos recursos \u2014 inserir um novo item na base. Em uma aplica\u00e7\u00e3o <strong>REST <\/strong>perfeita quando uma opera\u00e7\u00e3o \u00e9 executada com sucesso, retorna-se o <strong><a title=\"https:\/\/pt.wikipedia.org\/wiki\/Idempot%C3%AAncia\" href=\"https:\/\/pt.wikipedia.org\/wiki\/Idempot%C3%AAncia\">idempotente<\/a><\/strong> portanto seu uso n\u00e3o \u00e9 recomendado quando se precisa desse tipo de comportamento em uma requisi\u00e7\u00e3o. Fazendo duas requisi\u00e7\u00f5es <strong>POST<\/strong> id\u00eanticas o resultado mais comum ser\u00e1 duas respostas iguais com a mesma informa\u00e7\u00e3o mas ocasionalmente essa resposta pode mudar.<\/p>\n<p><strong>GET &#8211; READ\/para selecionar\/recuperar um recurso<\/strong><\/p>\n<p>O verbo HTTP GET \u00e9 usado para ler ou recuperar uma representa\u00e7\u00e3o de um recurso. Em um &#8220;cen\u00e1rio feliz&#8221;, uma requisi\u00e7\u00e3o GET retorna uma representa\u00e7\u00e3o em <strong>XML <\/strong>ou <strong>JSON <\/strong>e um <strong>HTTP<\/strong> <strong><a title=\"http:\/\/www.restapitutorial.com\/httpstatuscodes.html\" href=\"http:\/\/www.restapitutorial.com\/httpstatuscodes.html\">status code<\/a><\/strong> 200 (OK). Em um cen\u00e1rio de erro o retorno mais comum \u00e9 <strong>404 (NOT FOUND)<\/strong> ou <strong>400 (BAD REQUEST)<\/strong>.<br \/>\nDe acordo com o design da especifica\u00e7\u00e3o <strong>HTTP<\/strong>, o verbo <strong>GET <\/strong>(juntamente com o <strong>HEAD<\/strong>) \u00e9 usado apenas para ler informa\u00e7\u00f5es e n\u00e3o para alter\u00e1-la. Portanto quando usado dessa maneira \u00e9 considerado seguro. Ou seja, ou seja eles podem ser invocados sem risco de perda ou corrup\u00e7\u00e3o de dados \u2014 chamando uma vez tem o mesmo efeito de cham\u00e1-lo 10 vezes, ou nenhuma. Al\u00e9m disso, o verbo <strong>GET <\/strong>(e <strong>HEAD<\/strong>) \u00e9 idempotente, o que significa que se fizermos m\u00faltiplas requisi\u00e7\u00f5es teremos sempre o mesmo resultado.<br \/>\nVoc\u00ea nunca deveria expor opera\u00e7\u00f5es inseguras via <strong>GET <\/strong>\u2014 ele nunca deve ser usado para modificar informa\u00e7\u00f5es no servidor.<\/p>\n<p><strong>PUT &#8211; UPDATE\/para modificar um recurso<\/strong><\/p>\n<p>O verbo <strong>PUT <\/strong>\u00e9 comumente usado para atualizar informa\u00e7\u00f5es, colocando um recurso conhecido no (body) corpo da requisi\u00e7\u00e3o contendo novas informa\u00e7\u00f5es que representam o recurso original.<br \/>\nEntretanto, o verbo <strong>PUT <\/strong>tamb\u00e9m pode ser usado para criar um recurso caso o <strong>ID <\/strong>do mesmo seja definido pelo cliente ao inv\u00e9s do servidor. Em outras palavras se o verbo PUT \u00e9 proveniente de uma <strong>URI <\/strong>que n\u00e3o contenha um recurso com um ID preexistente. Nesse caso o corpo da requisi\u00e7\u00e3o cont\u00e9m a representa\u00e7\u00e3o de um recurso. Para muitos isso pode parecer complicado e confuso. Conseq\u00fcentemente, este verbo deve ser usado com modera\u00e7\u00e3o para a cria\u00e7\u00e3o de um novo recurso.<br \/>\nUma alternativa para isso \u00e9 utilizar o verbo <strong>POST<\/strong> para criar novos recursos com o ID definido pelo cliente setado no corpo da requisi\u00e7\u00e3o \u2014 caso n\u00e3o tenha o <strong>ID <\/strong>definido para o recurso deve-se usar o verbo <strong>POST<\/strong>(confira acima).<br \/>\nUm update bem sucedido, retorna um <strong>status code<\/strong> 200 (ou 204 quando n\u00e3o retorna nenhum conte\u00fado no body. Se estiver usando o verbo <strong>PUT<\/strong> para criar um novo recurso, o retorno deve ser um <strong>status code<\/strong> 201 em caso de uma cria\u00e7\u00e3o bem sucedida. O response body \u00e9 opcional \u2014 lembrando que quando ele \u00e9 exposto h\u00e1 um consumo maior de banda. Caso o cliente seja o respons\u00e1vel por definir o <strong>ID <\/strong>do recurso n\u00e3o \u00e9 necess\u00e1rio retornar um link para o mesmo via location header.<br \/>\nO verbo <strong>PUT <\/strong>n\u00e3o \u00e9 uma opera\u00e7\u00e3o segura, na medida em que modifica(ou cria) um recurso no servidor, mas ele \u00e9 idempotente. Em outras palavras, se voc\u00ea cria ou atualiza um recurso usando o verbo <strong>PUT <\/strong>e executa a mesma opera\u00e7\u00e3o de novo, o recurso ter\u00e1 o mesmo estado que na primeira execu\u00e7\u00e3o.<br \/>\nSe, por exemplo, voc\u00ea fizer uma requisi\u00e7\u00e3o <strong>PUT <\/strong>para um recurso que incrementa um contador dentro de um recurso, a requisi\u00e7\u00e3o perde o comportamento de idempotente. As vezes isso acontece sendo suficiente apenas documentar a requisi\u00e7\u00e3o como n\u00e3o idempotente. Entretanto, o recomendado para requisi\u00e7\u00f5es <strong>PUT <\/strong>\u00e9 implementar apenas requisi\u00e7\u00f5es idempotentes. Sendo assim \u00e9 fortemente recomendado o uso do verbo <strong>POST <\/strong>para opera\u00e7\u00f5es n\u00e3o idempotentes.<\/p>\n<p><strong>DELETE &#8211; DELETE\/para remover um recurso<\/strong><\/p>\n<p>O verbo DELETE \u00e9 f\u00e1cil de entender, ele \u00e9 usado para deletar um recurso identificado por uma URI.<br \/>\nEm uma dele\u00e7\u00e3o bem sucedida retorna-se um <strong>status code<\/strong> <strong>200 (OK)<\/strong> juntamente com um response body, possivelmente uma representa\u00e7\u00e3o do item deletado (o que acaba por demandar muita banda), ou uma response customizada. Ou retornar o <strong>status code<\/strong> <strong>204 (NO CONTENT)<\/strong> sem response body. Em outras palavras, um <strong>status code<\/strong> 204 sem corpo, ou <strong><a title=\"https:\/\/labs.omniti.com\/labs\/jsend\" href=\"https:\/\/labs.omniti.com\/labs\/jsend\">JSEND-style response<\/a><\/strong> com um <strong>status code<\/strong> 200 s\u00e3o as responses mais recomendadas.<br \/>\nAs opera\u00e7\u00f5es de <strong>DELETE <\/strong>s\u00e3o idempotentes. Se voc\u00ea deleta um recurso, ele \u00e9 removido sendo imposs\u00edvel repetir a opera\u00e7\u00e3o uma vez que o recurso n\u00e3o existe mais. Se voc\u00ea utilizar o verbo <strong>DELETE <\/strong>para decrementar um contador (dentro de um recurso), sua opera\u00e7\u00e3o <strong>DELETE <\/strong>n\u00e3o ser\u00e1 mais idempotente. Como dito anteriormente, estat\u00edsticas de uso e m\u00e9tricas podem ser atualizadas enquanto o servi\u00e7o \u00e9 considerado idempotente e as informa\u00e7\u00f5es do recursos permanecem inalteradas. \u00c9 recomendado o uso do verbo POST para opera\u00e7\u00f5es n\u00e3o idempotentes.<br \/>\nExiste uma recomenda\u00e7\u00e3o quanto a idempot\u00eancia do DELETE entretanto repetir uma requisi\u00e7\u00e3o de <strong>DELETE<\/strong> em um recurso, normalmente, retorna um <strong>status code<\/strong> 404 (NOT FOUND) uma vez que j\u00e1 foi removido e, portanto, n\u00e3o existe mais. Para muitos uma opera\u00e7\u00e3o de <strong>DELETE <\/strong>n\u00e3o \u00e9 idempotente, entretanto, o resultado final do recurso \u00e9 o mesmo. Retornar um <strong>status code<\/strong> 404 \u00e9 aceit\u00e1vel e comunica com precis\u00e3o o status da requisi\u00e7\u00e3o.<\/p>\n<p>Como podemos perceber, esses quatro verbos nos permite tra\u00e7ar uma certa analogia entre os verbos <strong>HTTP <\/strong>e o <strong>SQL<\/strong>. Observando a tabela abaixo isto fica um pouco mais claro.<\/p>\n<p><a href=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2015\/12\/image2.png\"><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-672\" src=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2015\/12\/image2.png\" alt=\"image2\" width=\"791\" height=\"553\" srcset=\"https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2015\/12\/image2.png 791w, https:\/\/www.semeru.com.br\/blog\/wp-content\/uploads\/2015\/12\/image2-300x209.png 300w\" sizes=\"(max-width: 791px) 100vw, 791px\" \/><\/a><\/p>\n<p>Al\u00e9m dos verbos mencionados anteriormente temos outros menos usados.<\/p>\n<p><strong>HEAD <\/strong>&#8211; O verbo <strong>HEAD<\/strong> possui uma funcionalidade similar ao verbo <strong>GET<\/strong>, exceto pelo fato do servidor retornar uma response line e headers, mas sem um entity-body.<br \/>\n<strong>TRACE <\/strong>&#8211; O verbo <strong>TRACE<\/strong> \u00e9 usado para recuperar o conte\u00fado de uma requisi\u00e7\u00e3o <strong>HTTP <\/strong>de volta podendo ser usado com o prop\u00f3sito de debug durante o processo de desenvolvimento.<br \/>\n<strong>OPTIONS <\/strong>&#8211; O verbo <strong>OPTIONS <\/strong>\u00e9 usado pelo cliente para encontrar opera\u00e7\u00f5es <strong>HTTP <\/strong>e outras op\u00e7\u00f5es suportadas pelo servidor. O cliente pode especificar uma <strong>URL <\/strong>para o verbo <strong>OPTIONS<\/strong> ou um asterisco (*) para se referir a todo o servidor.<br \/>\n<strong>CONNECT <\/strong>&#8211; O verbo <strong>CONNECT <\/strong>\u00e9 usado pelo cliente para estabelecer uma conex\u00e3o de rede com um servidor via <strong>HTTP<\/strong>.<br \/>\n<strong>PATCH<\/strong> &#8211; O verbo <strong><a title=\"https:\/\/tools.ietf.org\/html\/rfc5789\" href=\"https:\/\/tools.ietf.org\/html\/rfc5789\">PATCH<\/a><\/strong> pode ser usado para realizar updates parcias de um recurso. Por exemplo, quando voc\u00ea precisar alterar apenas um campo em um recurso, executar um POST com todo o objeto \u00e9 pesado e acarreta em um maior consumo de banda. Levando isso em conta a primeira coisa que vem em mente \u00e9: &#8220;por que n\u00e3o usar o PATCH ao inv\u00e9s do PUT para realisar atualiza\u00e7\u00f5es sempre?&#8221;. Simples o verbo PATCH pode ser um problema na medida em que n\u00e3o \u00e9 idempotente. Al\u00e9m disso minimizar seu uso previne curup\u00e7\u00e3o de dados por &#8220;colis\u00f5es&#8221; entre duas PATCH requests no mesmo recurso em um mesmo frame de tempo. Colis\u00f5es entre multiplas PATCH requests s\u00e3o mais perigosas que colis\u00f5s entre PUT requests por que exige que o cliente tenha informa\u00e7\u00f5es b\u00e1sicas do recurso ou ir\u00e3o corromp\u00ea-lo.<\/p>\n<p><strong>Formatos Suportados em Web Services RESTful<\/strong><\/p>\n<ul>\n<li>XML<\/li>\n<li>JSON<\/li>\n<li>CSV<\/li>\n<li>Texto<\/li>\n<li>Imagens<\/li>\n<li>HTML<\/li>\n<li>PDF<\/li>\n<li>bin\u00e1rio<\/li>\n<li>etc<\/li>\n<\/ul>\n<p><strong>Vantagens dos Web Services RESTful<\/strong><\/p>\n<ul>\n<li><strong>REST<\/strong> \u00e9 um padr\u00e3o arquitetural basicamente leve por natureza. Ent\u00e3o quando voc\u00ea tiver limita\u00e7\u00f5es de banda prefira web services <strong>REST<\/strong>;<\/li>\n<li>Desenvolvimento f\u00e1cil e r\u00e1pido;<\/li>\n<li>Grandes sites como <strong>Twitter<\/strong>, <strong>Yahoo<\/strong>, <strong>Google<\/strong>, <strong>Facebook <\/strong>usam este padr\u00e3o;<\/li>\n<li>Aplicativos Mobile tem ganhado cada vez mais espa\u00e7o e precisam interagir rapidamente com os servidores e o padr\u00e3o REST \u00e9 mais r\u00e1pido no processamento de dados das requests e responses.<\/li>\n<\/ul>\n<p><strong>Botando em pr\u00e1tica<\/strong><\/p>\n<p>Em breve estar\u00e3o dispon\u00edveis dois posts <a href=\"https:\/\/www.semeru.com.br\/blog\/criando-o-primeiro-endpoint-rest-com-springboot\/\">Criando o primeiro endpoint REST com SpringBoot<\/a> e <a href=\"https:\/\/www.semeru.com.br\/blog\/documentando-aplicacoes-restfull-com-springboot-e-swagger\/\">Documentando aplica\u00e7\u00f5es RESTfull com SpringBoot e Swagger <\/a> com exemplos pr\u00e1ticos.<\/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\"><br \/>\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\" \/><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_asp_net\" target=\"_blank\" rel=\"noopener\"><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\"> <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\"> <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\"> <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\"> <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\"> <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\"> <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\"> <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<h2>Refer\u00eancias:<\/h2>\n<p><a title=\"http:\/\/cxf.apache.org\/docs\/jax-rs.html\" href=\"http:\/\/cxf.apache.org\/docs\/jax-rs.html\">Apache CXF<\/a><br \/>\n<a title=\"http:\/\/docs.jboss.org\/resteasy\/docs\/3.0.7.Final\/userguide\/html\/\" href=\"http:\/\/docs.jboss.org\/resteasy\/docs\/3.0.7.Final\/userguide\/html\/\">JBoss RestEasy<\/a><br \/>\n<a title=\"https:\/\/jersey.java.net\/download.html\" href=\"https:\/\/jersey.java.net\/download.html\">Jersey<\/a><br \/>\n<a title=\"http:\/\/rest.elkstein.org\/\" href=\"http:\/\/rest.elkstein.org\/\">Elkstein<\/a><br \/>\n<a title=\"https:\/\/dzone.com\/articles\/introduction-to-restful-web-service-a-jax-rs-speci\" href=\"https:\/\/dzone.com\/articles\/introduction-to-restful-web-service-a-jax-rs-speci\">DZone<\/a><br \/>\n<a title=\"http:\/\/www.restapitutorial.com\/lessons\/httpmethods.html\" href=\"http:\/\/www.restapitutorial.com\/lessons\/httpmethods.html\">REST API Tutorial<\/a><br \/>\n<a title=\"http:\/\/restcookbook.com\/HTTP%20Methods\/patch\/#sthash.rbAjWA0E.dpuf\" href=\"http:\/\/restcookbook.com\/HTTP%20Methods\/patch\/#sthash.rbAjWA0E.dpuf\">The RESTful CookBook<\/a><br \/>\n<a title=\"http:\/\/www.tutorialspoint.com\/http\/http_methods.htm\" href=\"http:\/\/www.tutorialspoint.com\/http\/http_methods.htm\">Tutorials Point<\/a><\/p>\n<div align=\"right\"><div class=\"sharexyWidgetNoindexUniqueClassName\"><div id=\"shr_30896272\"><\/div><\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>Dando seq\u00fc\u00eancia a s\u00e9rie de postagens sobre Web-services neste post, discutiremos sobre a JAX-RS 2.0 a especifica\u00e7\u00e3o para servi\u00e7os baseados em RESTful. No mundo REST, voc\u00ea pode acessar tudo como um recurso e eles possuem um identificador \u00fanico a URI(Uniform Resource Identifier). Um servidor REST e seus clientes interagem usando o protocolo HTTP e seus [&#8230;]<\/p>\n<div align=\"right\">\n<div class=\"sharexyWidgetNoindexUniqueClassName\">\n<div id=\"shr_30896272\"><\/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,116,120,121,105],"tags":[205,204,206,207,194],"_links":{"self":[{"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/posts\/670"}],"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=670"}],"version-history":[{"count":20,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/posts\/670\/revisions"}],"predecessor-version":[{"id":1478,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/posts\/670\/revisions\/1478"}],"wp:attachment":[{"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/media?parent=670"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/categories?post=670"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.semeru.com.br\/blog\/wp-json\/wp\/v2\/tags?post=670"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}