{"id":1747,"date":"2024-10-23T16:08:00","date_gmt":"2024-10-23T19:08:00","guid":{"rendered":"https:\/\/www.erudio.com.br\/blog\/?p=1747"},"modified":"2024-11-02T18:47:58","modified_gmt":"2024-11-02T21:47:58","slug":"como-versionar-uma-api-rest","status":"publish","type":"post","link":"https:\/\/www.erudio.com.br\/blog\/como-versionar-uma-api-rest\/","title":{"rendered":"<strong>Como Versionar uma API REST<\/strong>"},"content":{"rendered":"\n<p>Se voc\u00ea n\u00e3o est\u00e1 muito familiarizado com APIs, pode estar se perguntando&#8230; por que toda essa confus\u00e3o em torno do <em><em>versionamento<\/em><\/em> de API&#8217;s?<\/p>\n\n\n\n<p>Se voc\u00ea j\u00e1 foi impactado por mudan\u00e7as em APIs, provavelmente \u00e9 voc\u00ea quem est\u00e1 preocupado. Se voc\u00ea \u00e9 o respons\u00e1vel por manter uma API, tamb\u00e9m pode estar lidando com perguntas desafiadoras como estas:<\/p>\n\n\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# Esta \u00e9 a vers\u00e3o 2 apenas dos produtos ou de toda a API?\n\/v2\/products\n\n# O que catalisou a mudan\u00e7a entre v1 e v2? Como elas s\u00e3o diferentes?\n\/v1\/products\n\/v2\/products\n<\/pre>\n\n\n\n<p>Essas perguntas sobre <em><em>versionamento<\/em><\/em> n\u00e3o s\u00e3o f\u00e1ceis de responder. Nem sempre \u00e9 claro a que a v1 ou v2 se refere. E n\u00e3o devemos simplesmente criar uma segunda vers\u00e3o de um <em>endpoint<\/em> quando a primeira parecer n\u00e3o ser mais suficiente.<\/p>\n\n\n\n<p>H\u00e1 raz\u00f5es claras pelas quais sua API precisa ter <em><em>versionamento<\/em><\/em>, e existem estrat\u00e9gias claras para navegar efetivamente pelas mudan\u00e7as na API.<\/p>\n\n\n\n<p>No entanto, descobri que a maioria dos desenvolvedores &#8211; incluindo eu mesmo, at\u00e9 aprender algumas li\u00e7\u00f5es da maneira mais dif\u00edcil &#8211; n\u00e3o conhece essas raz\u00f5es e estrat\u00e9gias.<\/p>\n\n\n\n<p>Este artigo busca destacar essas raz\u00f5es para o <em><em>versionamento<\/em><\/em> e estrat\u00e9gias para realiz\u00e1-lo. Vamos assumir um contexto de API REST, j\u00e1 que \u00e9 um padr\u00e3o para muitas API&#8217;s, e focar no aspecto de <em><em>versionamento<\/em><\/em>.<\/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>O que \u00e9 <em>Versionamento<\/em>?<\/h3>\n\n\n\n<p>Devemos come\u00e7ar esclarecendo o que significa o termo &#8220;versionamento de API&#8221;. Aqui est\u00e1 nossa defini\u00e7\u00e3o:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>O versionamento de API&#8217;s \u00e9 a pr\u00e1tica de gerenciar de maneira transparente as mudan\u00e7as na sua API.<\/p>\n<\/blockquote>\n\n\n\n<p><em><em>Versionamento<\/em><\/em> \u00e9 comunica\u00e7\u00e3o eficaz sobre mudan\u00e7as em sua API, para que os consumidores saibam o que esperar dela. Voc\u00ea est\u00e1 fornecendo dados ao p\u00fablico de alguma forma e precisa comunicar quando altera a maneira como esses dados s\u00e3o entregues.<\/p>\n\n\n\n<p>Isso se resume, na pr\u00e1tica, a gerenciar contratos de dados e mudan\u00e7as disruptivas. O primeiro \u00e9 o bloco de constru\u00e7\u00e3o principal da sua API e o \u00faltimo revela por que o v<em><em>ersionamento<\/em><\/em> \u00e9 necess\u00e1rio.<\/p>\n\n\n\n<h3>Contratos de Dados<\/h3>\n\n\n\n<p>Uma API \u00e9 uma <em>Application Programming Interface<\/em>, e uma interface \u00e9 uma fronteira compartilhada para troca de informa\u00e7\u00f5es. O contrato de dados \u00e9 o cora\u00e7\u00e3o dessa interface.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>Um contrato de dados \u00e9 um acordo sobre a estrutura e o conte\u00fado geral dos dados de request e\/ou response.<\/p>\n<\/blockquote>\n\n\n\n<p>Para ilustrar um contrato de dados, aqui est\u00e1 um corpo de response JSON b\u00e1sico:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>{\n  \"data\": [\n    {\n      \"id\": 1,\n      \"name\": \"Produto 1\"\n    },\n    {\n      \"id\": 2,\n      \"name\": \"Produto 2\"\n    }\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p>Esse \u00e9 um objeto com uma propriedade <code>data<\/code> que \u00e9 uma lista de produtos, cada um com uma propriedade <code>id<\/code> e <code>name<\/code>. Mas a propriedade <code>data<\/code> poderia facilmente ter sido chamada de <code>body<\/code>, e a propriedade <code>id<\/code> em cada produto poderia ser um GUID em vez de um n\u00famero inteiro. Se um \u00fanico produto estivesse sendo retornado, <code>data<\/code> poderia ser um objeto em vez de uma lista.<\/p>\n\n\n\n<p>Essas mudan\u00e7as aparentemente sutis teriam criado um acordo diferente, um contrato diferente, em rela\u00e7\u00e3o ao &#8220;formato&#8221; dos dados. O formato dos dados poderia se aplicar a nomes de propriedades, tipos de dados ou at\u00e9 mesmo ao formato esperado (JSON vs. XML).<\/p>\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>Por que o <em><em>Versionamento<\/em><\/em> \u00e9 Necess\u00e1rio?<\/h3>\n\n\n\n<p>Com APIs, algo t\u00e3o simples quanto mudar o nome de uma propriedade de <code>productId<\/code> para <code>productID<\/code> pode causar problemas para os consumidores. Isso aconteceu com nossa equipe na semana passada.<\/p>\n\n\n\n<p>Felizmente, t\u00ednhamos testes para capturar mudan\u00e7as no contrato da API. No entanto, n\u00e3o dever\u00edamos precisar desses testes, pois os respons\u00e1veis pela API deveriam saber que isso seria uma mudan\u00e7a disruptiva.<\/p>\n\n\n\n<h3>Mudan\u00e7as Disruptivas<\/h3>\n\n\n\n<p>Essa foi uma mudan\u00e7a disruptiva no contrato de dados acordado, porque a altera\u00e7\u00e3o deles nos for\u00e7ou a mudar nossa aplica\u00e7\u00e3o tamb\u00e9m.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p><em>O que constitui uma \u201cmudan\u00e7a disruptiva\u201d em um endpoint de API? <\/em>Qualquer mudan\u00e7a no seu contrato de API que force o consumidor a fazer uma altera\u00e7\u00e3o tamb\u00e9m.<\/p>\n<\/blockquote>\n\n\n\n<p>As mudan\u00e7as disruptivas geralmente se encaixam nas seguintes categorias:<\/p>\n\n\n\n<ul>\n<li>Mudan\u00e7a no formato de request\/response (por exemplo, de XML para JSON)<\/li>\n\n\n\n<li>Mudan\u00e7a no nome de uma propriedade (por exemplo, de <code>name<\/code> para <code>productName<\/code>) ou no tipo de dado de uma propriedade (por exemplo, de um n\u00famero inteiro para um n\u00famero de ponto flutuante)<\/li>\n\n\n\n<li>Adi\u00e7\u00e3o de um campo obrigat\u00f3rio na request (por exemplo, um novo <em>header <\/em>obrigat\u00f3rio ou uma propriedade no corpo da request)<\/li>\n\n\n\n<li>Remo\u00e7\u00e3o de uma propriedade na response (por exemplo, removendo <code>description<\/code> de um produto)<\/li>\n<\/ul>\n\n\n\n<h3>Gerenciamento de Mudan\u00e7as na API<\/h3>\n\n\n\n<p>Nunca \u00e9 s\u00e1bio ou gentil for\u00e7ar os consumidores de uma API a fazer uma mudan\u00e7a. Se voc\u00ea precisar fazer uma mudan\u00e7a disruptiva, \u00e9 para isso que o <em><em>versionamento<\/em><\/em> serve, e vamos cobrir as formas mais eficazes de versionar sua aplica\u00e7\u00e3o e seus <em>endpoints<\/em>.<\/p>\n\n\n\n<p>Mas primeiro, vamos discutir brevemente como evitar mudan\u00e7as disruptivas desde o in\u00edcio. Podemos chamar isso de gerenciamento de mudan\u00e7as de API.<\/p>\n\n\n\n<p>O gerenciamento eficaz de mudan\u00e7as no contexto de uma API \u00e9 resumido pelos seguintes princ\u00edpios:<\/p>\n\n\n\n<ol>\n<li>Continuar a dar suporte a propriedades\/<em>endpoints<\/em> existentes<\/li>\n\n\n\n<li>Adicionar novas propriedades\/<em>endpoints<\/em> em vez de alterar os existentes<\/li>\n\n\n\n<li>Descontinuar de forma planejada propriedades\/<em>endpoints<\/em> obsoletos<\/li>\n<\/ol>\n\n\n\n<p>Aqui est\u00e1 um exemplo que demonstra todos os tr\u00eas princ\u00edpios no contexto da response para request de dados do usu\u00e1rio:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code>{\n  \"data\": {\n    \"id\": 1,\n    \"name\": \"Carlos Ray Norris\",     \/\/ propriedade original\n    \"firstName\": \"Carlos\",           \/\/ nova propriedade\n    \"lastName\": \"Norris\",            \/\/ nova propriedade\n    \"alias\": \"Chuck\",                \/\/ propriedade obsoleta\n    \"aliases\": [\"Chuck\", \"Walker\"]   \/\/ nova propriedade\n  },\n  \"meta\": {\n    \"fieldNotes\": [\n      {\n        \"field\": \"alias\",\n        \"note\": \"Desativando em [data futura]. Por favor, use `aliases`.\"\n      }\n    ]\n  }\n}<\/code><\/pre>\n\n\n\n<p>Nesse exemplo, <code>name<\/code> era uma propriedade original. Os campos <code>firstName<\/code> e <code>lastName<\/code> est\u00e3o sendo implementados para fornecer uma op\u00e7\u00e3o mais granular, caso o consumidor queira exibir &#8220;Sr. Norris&#8221; com interpola\u00e7\u00e3o de string, sem precisar analisar o campo <code>name<\/code>. No entanto, a propriedade <code>name<\/code> continuar\u00e1 sendo suportada.<\/p>\n\n\n\n<p><code>alias<\/code>, por outro lado, ser\u00e1 descontinuada em favor do array <code>aliases<\/code>\u2014porque Chuck tem tantos apelidos\u2014e h\u00e1 uma nota na response indicando o cronograma de desativa\u00e7\u00e3o.<\/p>\n\n\n\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\n\n\n<h3>Como Versionar uma API?<\/h3>\n\n\n\n<p>Esses princ\u00edpios ajudar\u00e3o bastante na navega\u00e7\u00e3o de mudan\u00e7as em sua API sem a necessidade de lan\u00e7ar uma nova vers\u00e3o. No entanto, \u00e0s vezes isso \u00e9 inevit\u00e1vel, e se voc\u00ea precisar de um novo <em>data contract<\/em>, precisar\u00e1 de uma nova vers\u00e3o do seu <em>endpoint<\/em>. Portanto, voc\u00ea precisar\u00e1 comunicar isso ao p\u00fablico de alguma forma.<\/p>\n\n\n\n<p>A t\u00edtulo de nota, observe que n\u00e3o estamos falando sobre a vers\u00e3o da base de <em>c\u00f3digo<\/em> subjacente. Assim, se voc\u00ea estiver usando <a href=\"https:\/\/semver.org\/\">versionamento sem\u00e2ntico<\/a> para sua aplica\u00e7\u00e3o que tamb\u00e9m suporta uma <em>API<\/em> p\u00fablica, provavelmente voc\u00ea vai querer separar esses sistemas de versionamento.<\/p>\n\n\n\n<p>Como voc\u00ea cria uma nova vers\u00e3o da sua <em>API<\/em>? Quais s\u00e3o os diferentes m\u00e9todos para faz\u00ea-lo? Voc\u00ea precisar\u00e1 determinar qual tipo de estrat\u00e9gia de versionamento deseja adotar em geral e, em seguida, ao desenvolver e manter sua <em>API<\/em>, precisar\u00e1 determinar o escopo de cada mudan\u00e7a de vers\u00e3o.<\/p>\n\n\n\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\n\n\n<p><strong>Escopo<\/strong><br>Vamos abordar o escopo primeiro. Como exploramos acima, \u00e0s vezes os <em>data contracts<\/em> ser\u00e3o comprometidos por uma mudan\u00e7a disruptiva, e isso significa que precisaremos fornecer uma nova vers\u00e3o do <em>data contract<\/em>. Isso pode significar uma nova vers\u00e3o de um <em>endpoint<\/em> ou pode significar uma mudan\u00e7a em um escopo de aplica\u00e7\u00e3o mais global.<\/p>\n\n\n\n<p>Podemos pensar em n\u00edveis de mudan\u00e7a de escopo dentro de uma analogia de \u00e1rvore:<\/p>\n\n\n\n<ul>\n<li><strong>Folha<\/strong> <strong><em>(leaf)<\/em><\/strong> &#8211; Uma mudan\u00e7a em um <em>endpoint<\/em> isolado, sem rela\u00e7\u00e3o com outros <em>endpoints<\/em>.<\/li>\n\n\n\n<li><strong>Ramo<\/strong> <strong><em>(branch)<\/em><\/strong> &#8211; Uma mudan\u00e7a em um grupo de <em>endpoints<\/em> ou em um recurso acessado atrav\u00e9s de v\u00e1rios <em>endpoints<\/em>.<\/li>\n\n\n\n<li><strong>Tronco<\/strong> <strong><em>(trunk)<\/em><\/strong> &#8211; Uma mudan\u00e7a em n\u00edvel de aplica\u00e7\u00e3o, que justifica uma mudan\u00e7a de vers\u00e3o na maioria ou em todos os <em>endpoints<\/em>.<\/li>\n\n\n\n<li><strong>Raiz<\/strong> <strong><em>(Root)<\/em><\/strong> &#8211; Uma mudan\u00e7a que afeta o acesso a todos os recursos da <em>API<\/em> de todas as vers\u00f5es.<\/li>\n<\/ul>\n\n\n\n<p>Como voc\u00ea pode ver, ao passar de folha para raiz, as mudan\u00e7as se tornam progressivamente mais impactantes e globais em escopo.<\/p>\n\n\n\n<p>O escopo da folha pode frequentemente ser tratado por meio de uma gest\u00e3o eficaz de mudan\u00e7as na <em>API<\/em>. Caso contr\u00e1rio, basta criar um novo <em>endpoint<\/em> com o novo <em>data contract<\/em> de recurso.<\/p>\n\n\n\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\n\n\n<p>Um ramo \u00e9 um pouco mais complicado, dependendo de quantos <em>endpoints<\/em> s\u00e3o afetados pela mudan\u00e7a do <em>data contract<\/em> no recurso em quest\u00e3o. Se as mudan\u00e7as forem relativamente restritas a um grupo claro de <em>endpoints<\/em> relacionados, voc\u00ea pode potencialmente navegar por isso introduzindo um novo nome para o recurso e atualizando sua documenta\u00e7\u00e3o de acordo.<\/p>\n\n\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n# variants, que possuem uma mudan\u00e7a disruptiva \u00e9 acessada em m\u00faltiplas rotas\n\/variants\n\/products\/:id\/variants\n\n# n\u00f3s introduzimos product-variants em vez disso\n\/product-variants\n\/products\/:id\/product-variants\n<\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Um tronco refere-se a mudan\u00e7as em n\u00edvel de aplica\u00e7\u00e3o que s\u00e3o frequentemente resultado de uma mudan\u00e7a em uma das seguintes categorias:<\/p>\n\n\n\n<ul>\n<li>Formato (por exemplo, de XML para JSON)<\/li>\n\n\n\n<li>Especifica\u00e7\u00e3o (por exemplo, de uma interna para JSON <em>API<\/em> ou <em>Open API<\/em>)<\/li>\n\n\n\n<li><em>Headers<\/em> obrigat\u00f3rios (por exemplo, para autentica\u00e7\u00e3o\/autoriza\u00e7\u00e3o)<\/li>\n<\/ul>\n\n\n\n<p>Essas mudan\u00e7as necessitar\u00e3o uma altera\u00e7\u00e3o na vers\u00e3o geral da sua <em>API<\/em>, ent\u00e3o voc\u00ea deve planejar cuidadosamente e executar a transi\u00e7\u00e3o de forma adequada.<\/p>\n\n\n\n<p>Uma mudan\u00e7a de raiz obrigar\u00e1 voc\u00ea a ir um passo al\u00e9m para garantir que todos os consumidores de todas as vers\u00f5es da sua <em>API<\/em> estejam cientes da mudan\u00e7a.<\/p>\n\n\n\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\n\n\n<p><strong>Tipos de Versionamento de API<\/strong><br>\u00c0 medida que nos voltamos para diferentes tipos de versionamento de <em>API<\/em>, queremos usar essas percep\u00e7\u00f5es sobre os v\u00e1rios escopos de mudan\u00e7as na <em>API<\/em> para avaliar os tipos. Cada abordagem tem seu pr\u00f3prio conjunto de pontos fortes e fracos em rela\u00e7\u00e3o a mudan\u00e7as com base em seu escopo.<\/p>\n\n\n\n<p>Existem v\u00e1rios m\u00e9todos para gerenciar a vers\u00e3o da sua <em>API<\/em>. O versionamento por <em>Path<\/em> de URI \u00e9 o mais comum.<\/p>\n\n\n\n<p><strong>Path de URI<\/strong><\/p>\n\n\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nhttp:\/\/www.example.com\/api\/v1\/products\nhttp:\/\/api.example.com\/v1\/products\n<\/pre>\n\n\n\n<p>Essa estrat\u00e9gia envolve colocar o n\u00famero da vers\u00e3o no <em>Path<\/em> do URI e \u00e9 frequentemente feita com o prefixo &#8220;v&#8221;. Mais frequentemente do que n\u00e3o, os projetistas de <em>API<\/em> usam isso para se referir \u00e0 vers\u00e3o de sua aplica\u00e7\u00e3o (ou seja, &#8220;tronco&#8221;) em vez da vers\u00e3o do <em>endpoint<\/em> (ou seja, &#8220;folha&#8221; ou &#8220;ramo&#8221;), mas isso nem sempre \u00e9 uma suposi\u00e7\u00e3o segura.<\/p>\n\n\n\n<p>O versionamento por <em>Path<\/em> de URI implica lan\u00e7amentos orquestrados de vers\u00f5es de aplica\u00e7\u00f5es que requerer\u00e3o uma das duas abordagens: manter uma vers\u00e3o enquanto desenvolve uma nova ou for\u00e7ar os consumidores a esperar por novos recursos at\u00e9 que a nova vers\u00e3o seja lan\u00e7ada. Isso tamb\u00e9m significa que voc\u00ea precisaria levar adiante qualquer <em>endpoint<\/em> que n\u00e3o tenha mudado de vers\u00e3o para vers\u00e3o. No entanto, para <em>APIs<\/em> com volatilidade relativamente baixa, ainda \u00e9 uma op\u00e7\u00e3o razo\u00e1vel.<\/p>\n\n\n\n<p>Voc\u00ea provavelmente n\u00e3o gostaria de relacionar seu n\u00famero de vers\u00e3o ao do <em>endpoint<\/em> ou recurso, porque isso facilmente resultaria em algo como uma v4 de produtos, mas uma v1 de variantes, o que seria bastante confuso.<\/p>\n\n\n\n<p><strong>Query Params<\/strong><br><\/p>\n\n\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nhttp:\/\/www.example.com\/api\/products?version=1\n<\/pre>\n\n\n\n<p>Esse tipo de versionamento adiciona um par\u00e2metro de consulta \u00e0 requisi\u00e7\u00e3o que indica a vers\u00e3o. Muito flex\u00edvel em termos de requisitar a vers\u00e3o do recurso que voc\u00ea gostaria no n\u00edvel &#8220;folha&#8221;, mas n\u00e3o possui no\u00e7\u00e3o da vers\u00e3o geral da <em>API<\/em> e se presta aos mesmos problemas de desincroniza\u00e7\u00e3o mencionados no coment\u00e1rio acima sobre o versionamento em n\u00edvel de <em>endpoint<\/em> do <em>Path<\/em> de URI.<\/p>\n\n\n\n<p><strong><em>Header<\/em><\/strong><br><\/p>\n\n\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nAccept: version=1.0\n<\/pre>\n\n\n\n<p>A abordagem de <em>header <\/em>\u00e9 aquela que oferece mais granularidade ao fornecer a vers\u00e3o requisitada de qualquer recurso dado.<\/p>\n\n\n\n<p>No entanto, est\u00e1 oculta no objeto de requisi\u00e7\u00e3o e n\u00e3o \u00e9 t\u00e3o transparente quanto a op\u00e7\u00e3o de <em>Path<\/em> de URI. Tamb\u00e9m ainda \u00e9 dif\u00edcil dizer se 1.0 se refere \u00e0 vers\u00e3o do <em>endpoint<\/em> ou da pr\u00f3pria <em>API<\/em>.<\/p>\n\n\n\n<p><strong>Integra\u00e7\u00e3o de Tipos<\/strong><br>Cada uma dessas abordagens parece ter a fraqueza de favorecer um escopo &#8220;folha&#8221; ou &#8220;tronco&#8221;, mas n\u00e3o suportar ambos.<\/p>\n\n\n\n<p>Se voc\u00ea precisa manter a vers\u00e3o geral da <em>API<\/em> e tamb\u00e9m fornecer suporte para v\u00e1rias vers\u00f5es de recursos, considere uma combina\u00e7\u00e3o dos tipos <em>Path<\/em> de URI e <strong><em>Query Params<\/em><\/strong>, ou uma abordagem de <em>header <\/em>mais avan\u00e7ada.<\/p>\n\n\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n\n# Combina\u00e7\u00e3o de Path de URI e query params\nhttp:\/\/api.example.com\/v1\/products?version=1\nhttp:\/\/api.example.com\/v1\/products?version=2\n\n# Headers estendidos, para http:\/\/api.example.com\/products\nAccept: api-version=1; resource-version=1\nAccept: api-version=1; resource-version=2\n\n<\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Conclus\u00e3o<\/strong><br>Cobrimos muitos aspectos aqui, ent\u00e3o vamos recapitular:<\/p>\n\n\n\n<ul>\n<li>O versionamento de <em>API<\/em> \u00e9 a pr\u00e1tica de gerenciar mudan\u00e7as em sua <em>API<\/em> de forma transparente.<\/li>\n\n\n\n<li>Gerenciar uma <em>API<\/em> se resume a definir e evoluir <em>data contracts<\/em> e lidar com mudan\u00e7as disruptivas.<\/li>\n\n\n\n<li>A maneira mais eficaz de evoluir sua <em>API<\/em> sem mudan\u00e7as disruptivas \u00e9 seguir princ\u00edpios eficazes de gest\u00e3o de mudan\u00e7as na <em>API<\/em>.<\/li>\n\n\n\n<li>Para a maioria das <em>APIs<\/em>, o versionamento no <em>Path<\/em> de URI \u00e9 a solu\u00e7\u00e3o mais direta.<\/li>\n\n\n\n<li>Para <em>APIs<\/em> mais complexas ou vol\u00e1teis, voc\u00ea pode gerenciar v\u00e1rios escopos de mudan\u00e7as empregando uma integra\u00e7\u00e3o das abordagens de <em>Path<\/em> de URI e <em>query params<\/em>.<\/li>\n<\/ul>\n\n\n\n<p>Embora esses princ\u00edpios devam fornecer uma dire\u00e7\u00e3o clara sobre como gerenciar efetivamente as mudan\u00e7as em suas <em>APIs<\/em>, evoluir uma <em>API<\/em> \u00e9 potencialmente mais uma arte do que uma ci\u00eancia. Isso requer reflex\u00e3o e previs\u00e3o para criar e manter uma <em>API<\/em> confi\u00e1vel.<\/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>Se voc\u00ea n\u00e3o est\u00e1 muito familiarizado com APIs, pode estar se perguntando&#8230; por que toda essa confus\u00e3o em torno do versionamento de API&#8217;s? Se voc\u00ea j\u00e1 foi impactado por mudan\u00e7as em APIs, provavelmente \u00e9 voc\u00ea quem est\u00e1 preocupado. Se voc\u00ea \u00e9 o respons\u00e1vel por manter uma API, tamb\u00e9m pode estar lidando com perguntas desafiadoras como [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1768,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[11,305,311,318,96,314,319],"tags":[132,323,321,324,221,322,316,320],"_links":{"self":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/1747"}],"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=1747"}],"version-history":[{"count":49,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/1747\/revisions"}],"predecessor-version":[{"id":1797,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/1747\/revisions\/1797"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/media\/1768"}],"wp:attachment":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/media?parent=1747"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/categories?post=1747"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/tags?post=1747"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}