понедельник, 18 июня 2018 г.

Estratégia de versão do api


Formas de versão da sua API, parte 2.
Esta é a segunda parte de uma série sobre o versionamento de API. A Parte Um cobriu os métodos predominantes para versionar sua API e permitir que os clientes codificassem contra uma versão específica. Eu sugiro que você leia esse post (pelo menos dê uma olhada na introdução!) Antes deste, pois ele fornece algum contexto necessário. Nele, insinuei que outro método que utiliza alguns conceitos pouco conhecidos da especificação do cabeçalho Accepts pode permitir que você crie uma API sem versão. Eu vou admitir na frente, no entanto, é um pouco errado, mas eu acho que ainda é importante. Você ainda pode atualizar as coisas na API, mas não está fazendo o versionamento da interface em si. Você está meramente controlando as representações de recursos.
A alteração mais comum em qualquer API arquitetada REST é adicionar, alterar ou remover campos dos recursos. Novas informações são adicionadas ou podem estar em um formato diferente. Informações podem se tornar indisponíveis. Você também pode adicionar, mover ou remover recursos. Dependendo da arquitetura da API, os verbos HTTP podem significar coisas ligeiramente diferentes. Tudo isso normalmente exigiria um incremento de versão da API se eles causassem a quebra de aplicativos existentes. Com um pouco de previsão, no entanto, sua API pode mudar sem exigir uma estratégia de versão de API inteira.
Arquiteto de uma interface sem versão:
Use esquemas de URI sane: / api / collection_name / resource_id Siga as definições dos métodos HTTP A inclusão de recursos deve ser sempre compatível com versões anteriores A remoção de recursos teria que ser feita entre versões de qualquer maneira Os recursos móveis podem ser manipulados por códigos HTTP de redirecionamento.
Representações de recurso de versão:
Usar o cabeçalho Aceitar A adição de informações deve sempre ser compatível com versões anteriores A remoção de informações teria que ser feita em versões de qualquer maneira. A movimentação de informações pode ser feita com a opção Aceitar o controle de versão.
Arquitetando uma API sem versão.
Deixe-me começar dizendo que reconheço que uma API sem versão é um pouco ideal, e uma API com uma estratégia de versão bem pensada é preferível a uma API com uma tentativa mal pensada de não usar a versão. Não há vergonha em dizer que você acha que precisa de versionamento, nem todas as APIs possíveis podem se encaixar nessa estratégia sem versão. Ele realmente funciona apenas para APIs baseadas em REST-architected, manipulação de recursos que seguem os padrões vigentes. Dito isso, uma grande quantidade de APIs pode ser retrabalhada para se encaixar neste estilo. Além disso, isso é destinado a APIs de back-end, e não a APIs que fazem interface com seu front-end da web. Na minha opinião, essas devem ser quase sempre APIs separadas, para que você possa atualizar a funcionalidade de front-end da web no seu próprio ritmo sem se preocupar com os usuários da API. Eu sei que, pessoalmente, sou muito mais negligente na minha sequência de padrões para APIs de front-end.
O primeiro passo para entender como criar uma API sem versão é saber que você não quer fazer a versão da própria versão. Isso significa que você não deseja alterar como e onde as informações são armazenadas e acessadas. Em termos práticos, esta é a estrutura da URI. Até mesmo essa regra pode ser distorcida, é claro - embutida na especificação HTTP são redirecionamentos! Se você moveu informações, basta fornecer um redirecionamento permanente para o novo URI. Agora, o que acontece se você remover um recurso?
Há dois motivos pelos quais um determinado URI pode ser removido de uma API típica: o próprio tipo de recurso foi removido ou, mais comumente, essa representação particular do recurso não é mais suportada. Neste último caso, você não está realmente aderindo à arquitetura REST: A representação de recursos deve ser dissociada da URI. No primeiro caso, se todo o tipo de recurso não estiver mais acessível, provavelmente é por um motivo comercial, e nesse caso você também o removerá de todas as versões anteriores da API. Nesse caso, o controle de versão não lhe dava nada, não é mesmo?
Adicionar recursos ou informações a recursos deve sempre ser uma alteração compatível com versões anteriores. Se você estiver usando o JSON, adicionar elementos aos recursos existentes deve ser fácil. Mesmo se você tiver um esquema XML, você pode simplesmente adicioná-los ao esquema definido e alertar os clientes que podem ter baixado sua própria cópia do esquema para atualizá-lo. Se você quiser adicionar um recurso totalmente novo, basta adicioná-lo. Ninguém deve ser afetado.
Provavelmente, a coisa mais difícil de fazer sem versão é qualquer alteração no que acontece quando você executa um método específico em uma API específica. Por exemplo, se você costumava POSTAR para / api / foo / e criar um novo recurso foo para você, mas agora deseja que ele edite um recurso foo existente. O melhor que posso lhe dizer é que não siga as definições do método de especificação HTTP recomendadas explicitamente:
GET / api / foo / ou GET / api / foo / 1 recupera recursos ou coleções de recursos e é idempotente (repetitivo com os mesmos resultados) POST / api / foo / cria novos recursos e NÃO é idempotente (a repetição cria mais recursos) PUT / api / foo / 1 atualiza ou cria um recurso específico inteiro e é idempotente PATCH / api / foo / 1 (padrão proposto) atualiza campos de um recurso específico e é idempotente DELETE / api / foo / 1 exclui um recurso (às vezes, coleções de recursos) e é idempotente.
Tecnicamente, acho que DELETE deveria notificar de alguma forma se o recurso não existia em primeiro lugar e uma maneira correta de fazer isso seria um erro, mas eu vou adiar isso. OPÇÕES e CABEÇA são usadas menos e se você as estiver usando, você provavelmente saberá o que você está fazendo de qualquer maneira. Se você estiver usando o PATCH, saiba que ele não é um padrão bem suportado e muitas APIs aceitam solicitações PUT incompletas e atualizam apenas os campos alterados. Acho que isso é bom, desde que seja um comportamento bem documentado e bem documentado, dado um suporte PATCH irregular, pelo menos até que seja mais amplamente aceitável.
Muitas vezes, os recursos são modificados pelas solicitações POST. Um formulário é enviado, você interpreta os dados e altera um recurso. Esse é um padrão comum em APIs de front-end e, como mencionei acima, tudo bem. Não é perfeito, mas está bem. Em uma API de back-end, isso não deveria acontecer! Use uma solicitação PUT ou PATCH e defina explicitamente o que você deseja que o novo recurso seja. Uma desculpa comum é que as versões antigas do IE não suportam PUT ou PATCH, mas esta é uma API de back-end, está bem! Todas as grandes bibliotecas que conheço, pelo menos, suportam o PUT - se você estiver usando um que não o faça, provavelmente deve procurar em outro lugar.
Em suma, um pré-requisito para o versionlessness é que todos os recursos que você tem devem poder ser acessados ​​e manipulados em uma fasion consistente, com as únicas diretivas sendo o URI para o recurso, o método HTTP e os dados que representam o próprio recurso. Se você estiver manipulando um único recurso lógico - digamos, um perfil de usuário - de vários URIs, provavelmente encontrará situações em que precisa de uma versão.
Representações de recursos de controle de versão.
Como mencionei na introdução, as próprias representações de recursos transferidas para o cliente podem e provavelmente devem ser versionadas. A beleza dessa abordagem é que cada recurso pode ser versionado de forma independente. Se você alterar um recurso e, em seguida, um mês depois, decidir alterar um recurso diferente, não será necessário incrementar um contador de versões da API duas vezes. Cada versão de recurso é incrementada individualmente. Observe que não estou falando sobre a versão dos recursos em si, apenas a representação do recurso. Se você tiver um recurso com versão, por exemplo, um documento que tenha revisões anteriores disponíveis, elas devem ser acessadas separadamente do que o método que eu estou descrevendo aqui.
Familiarizar-se com a especificação do cabeçalho Accept provavelmente ajudará você a entender a verdadeira profundidade de quão longe as especificações podem ir para a proteção do futuro. Quase todo mundo sabe que o cabeçalho Accepts especifica que tipo de MIME-Type o solicitante espera, como application / json. Poucos sabem que ele pode não apenas especificar um tipo, mas também especificar vários tipos aceitáveis, bem como parâmetros em cada tipo. Para representar representações de recursos de versão, vamos aproveitar os parâmetros de tipo.
Eu pulo e considero o seguinte:
Mesmo sem entender completamente o cabeçalho Aceita, você provavelmente pode adivinhar que essa cadeia implica que ele espera o tipo application / vnd. example. foo no formato json, versão 2, se disponível, e qualquer versão, caso contrário. Analisar o cabeçalho Aceita de maneira consistente com a especificação pode ser difícil somente porque muitas bibliotecas não o analisam imediatamente.
Então, quando você deve representar representações de recursos? Como mencionei acima, se você estiver removendo informações sobre um recurso, provavelmente é por motivo empresarial que você não quer mais que ele seja exposto. Na idade atual de transmissão compactada, há pouco ganho para remover informações simplesmente porque você não acha que é mais útil. A adição de informações deve sempre ser possível de ser feita de maneira compatível com versões anteriores. Você pode querer a versão em casos de alterar o nome e / ou o tipo de um campo, por exemplo, se você quiser (o exemplo real do mundo real!) Redirecionar um campo booleano rotulado & # 8220; ativado & # 8221; para um mais genérico & # 8220; status & # 8221; tipo enum.
Agora, como faço isso?
Infelizmente, muito do que eu tenho discutido aqui tem pouco ou nenhum apoio amplo na comunidade de pessoas que estão construindo APIs amplamente usadas. Eu suspeito que nenhuma pequena parte disso seja devido à dificuldade de implementá-las em um aplicativo do mundo real. Dependendo da sua plataforma, pode ser fácil ou difícil, e algumas bibliotecas suportarão uma estratégia de controle de versões como essa. O mais próximo que eu sei é se o node-restify, que suporta roteamento versionado baseado em um cabeçalho de versão aceita.
Eu vou estar passando por algumas bibliotecas e tentar estendê-las para dar suporte a versões no futuro. Possivelmente tentando minha própria biblioteca que faz muito disso de graça. Quanto mais fácil para um desenvolvedor escrever código compatível com os padrões, maior a probabilidade de adotá-lo, porque no final se trata de facilidade de desenvolvimento versus adesão aos padrões, acho que todos nós sabemos que a facilidade vencerá toda vez .

Quatro estratégias de versionamento da API REST.
Este artigo descreve quatro estratégias de versão de API REST comuns e explica como nós atualizamos a API REST no xMatters.
No xMatters, seguimos a especificação SemVer & # 8211; nós atualizamos a versão principal da API sempre que introduzimos as alterações de quebra. Internamente, atualizamos as versões menores e de correção sempre que adicionamos funcionalidade e atualizações compatíveis com versões anteriores. Quando lançamos uma nova versão principal da API REST xMatters, os clientes podem optar por continuar usando uma versão principal existente ou migrar para a nova.
O REST é de longe o estilo arquitetônico mais proeminente usado atualmente para expor serviços a terceiros pela Internet. Ele usa o padrão HTTP em vez de protocolos mais complexos, como SOAP ou RPC. A razão pela qual o REST tem sido tão bem-sucedido é que ele imita o funcionamento da Web:
Sem estado: não retém o contexto do cliente entre pedidos. Cache: depende de regras de armazenamento em cache de HTTP orientado a cliente / servidor: separa as preocupações entre clientes e servidores. Camadas: aproveita um sistema em camadas e uma interface unificada.
Quatro estratégias comuns de versionamento da API REST.
Existem quatro maneiras comuns de atualizar uma API REST.
1. Versionamento através do caminho do URI.
Uma maneira de atualizar uma API REST é incluir o número da versão no caminho da URL.
Essa estratégia é usada pela xMatters e por outras empresas, como Facebook, Twitter, Airbnb e outras.
Essa solução geralmente usa o roteamento de URI para apontar para uma versão específica da API. Como as chaves de cache (nesta situação, URIs) são alteradas por versão, os clientes podem facilmente armazenar recursos em cache. Quando uma nova versão da API REST é lançada, ela é percebida como uma nova entrada no cache.
A versão interna da API é a seguinte:
Versão principal: a versão usada no URI e denota alterações significativas na API. Internamente, uma nova versão principal implica a criação de uma nova API e o número da versão é usado para rotear para o host correto.
Versões menores e de patch: são transparentes para o cliente e usadas internamente para atualizações compatíveis com versões anteriores. Eles geralmente são comunicados nos logs de alterações para informar os clientes sobre uma nova funcionalidade ou uma correção de bug.
Essa solução tem uma pegada bem grande na base de código, pois a introdução de alterações significativas implica a ramificação de toda a API.
2. Versionamento através de parâmetros de consulta.
Outra opção para versionar uma API REST é incluir o número da versão como um parâmetro de consulta.
Essa é uma maneira direta de criar versões de uma API do ponto de vista da implementação. Também é fácil usar como padrão a versão mais recente, se um parâmetro de consulta não for especificado.
A principal desvantagem em comparação com o versionamento de URI é a dificuldade de roteamento. Os parâmetros de consulta são, na verdade, mais difíceis de usar para solicitações de roteamento para a versão adequada da API.
3. Versionamento através de cabeçalhos personalizados.
As APIs REST também podem ter versões, fornecendo cabeçalhos personalizados com o número da versão incluído como um atributo.
A principal diferença entre essa abordagem e as duas anteriores é que ela não sobrecarrega o URI com informações de versão.
4. Versionamento através de negociação de conteúdo.
curl - H & # 8220; Aceitar: aplicativo / vnd. xm. device + json; versão = 1 e # 8221; exemplo / api / products.
A última estratégia que estamos abordando é o controle de versão através da negociação de conteúdo.
Essa abordagem nos permite versionar uma única representação de recurso em vez de versionar toda a API, o que nos dá um controle mais granular sobre o controle de versão. Ele também cria uma pegada menor na base de código, já que não precisamos forçar o aplicativo inteiro ao criar uma nova versão. Outra vantagem dessa abordagem é que ela não exige a implementação de regras de roteamento de URI introduzidas pelo controle de versão por meio do caminho do URI.
Uma das desvantagens dessa abordagem é que ela é menos acessível do que APIs com versão de URI: a exigência de cabeçalhos HTTP com tipos de mídia dificulta o teste e a exploração da API usando um navegador.
A negociação de conteúdo é uma abordagem mais granular porque ela representa representações de recursos em vez de versionar toda a API, mas também apresenta um alto custo de implementação para clientes e desenvolvedores. Mais frequentemente do que não, a negociação de conteúdo precisa ser implementada a partir do zero, pois há poucas bibliotecas que oferecem isso de imediato. As outras abordagens são mais fáceis de implementar e usar, mas limitam a capacidade do desenvolvedor de refatorar devido ao alto custo da introdução de alterações significativas no contrato da API.
Quaisquer pensamentos ou recomendações? Deixe um comentário abaixo!
White Paper Gratuito: Aprenda sobre o Standard + Case.
Saiba mais sobre como adotar uma abordagem holística da TI em Rob England em seu blog, The IT Skeptic e em seus livros, incluindo o Plus! A abordagem padrão + caso. Para obter mais informações, leia o novo white paper de Rob sobre como transformar situações indefinidas de Case Management em novos modelos de resposta padrão, escritos para xMatters: Standard + Case: como os modelos de resposta de TI conduzem operações modernas.
Precisamos fazer o empacotamento (pasta) de acordo com a versão principal?
Outra questão é, como a versão do esquema se a mudança Api exigir mudança nas tabelas de banco de dados. algum link?
Uma coisa que não é documentada com muita frequência é como gerenciar o código e todas as versões suportadas pela API.
Estou interessado em encontrar um bom padrão para gerenciar nosso código e evitar o pesadelo da versão.
Minha implementação da terceira abordagem para o spring-webmvc:

Seu versionamento de API está errado, e é por isso que decidi fazer isso de três formas diferentes e erradas.
No final, decidi que a maneira mais justa e equilibrada era irritar todo mundo igualmente. É claro que estou falando sobre versionamento de APIs e não desde as ótimas guias # x201C versus espaços & # x201D; debate tenho visto tantas crenças fortes em campos totalmente diferentes.
Isso foi ótimo. Quando eu construí Eu fui pwned? (HIBP) no final de novembro, foi concebido para ser um serviço simples e rápido que algumas pessoas usariam. Eu acho que é justo dizer que os dois primeiros pontos foram alcançados, mas não o último. Não era um "número um", na verdade, no final da primeira semana, era mais do que o Google Analytics poderia suportar. O ponto é que você não pode sempre prever o futuro quando você escreve sua API e em algum momento você pode precisar mudar algo que as pessoas já dependem.
Mas aqui está o problema & # x2013; toda vez que você começa a falar sobre qualquer coisa relacionada a APIs via HTTP, isso acontece:
Todo caminho que você vira, há diferentes filosoficos sobre o caminho certo & # x201D; e muito para trás e para frente no REST, o que é RESTful, o que não é e se é importante. Vamos falar sobre as alterações da API, o impacto sobre as versões, por que há tantas idéias divergentes sobre como isso deve ser feito e, por fim, por que nenhuma das brincadeiras é tão importante quanto realmente fazer as coisas.
Puxando mais dados de violação.
Tendo em mente que a mesma API é usada para o recurso de pesquisa no site e agora também por terceiros criando tudo, de aplicativos de smartphone a ferramentas de teste de penetração, a resposta acima funcionou bem no começo, mas foi limitada. Por exemplo, esta resposta não funciona tão bem:
Por quê? Porque & # x201C; BattlefieldHeroes & # x201D; é o Pascal-cased que é ótimo para combinar com classes CSS codificadas (embora provavelmente não seja uma boa abordagem a longo prazo) e por ter um & # x201C; stable & # x201D; nome para se referir a (eu não vou alterá-lo, mesmo que haja uma segunda violação), mas não é adequado para exibição como um título. Tudo isso sai do Armazenamento de Tabelas do Azure e eu entro no SQL Azure para extrair dados relacionais que realmente descrevem a violação. Um dos atributos nesse armazenamento relacional é o nome que você vê acima.
O que eu realmente queria fazer era algo mais assim:
Pegue? Para o ponto anterior sobre o nome da violação, que ainda está lá no atributo name, mas agora temos um título também. Isto é o que você mostra para as pessoas & # x2013; & # x201C; Battlefield Heroes & # x201D; & # x2013; mas mais importante, se o Gawker for penhorado novamente, posso nomear a violação de algo como Gawker2014 e o título pode ser algo amigável ao longo das linhas de Gawker (Ataque Eletrônico do Exército Sírio) & # x201D ;. Ele segmenta o que é estável e previsível daquilo que não é e significa que as pessoas podem criar dependências, como imagens ou outros recursos, no atributo name.
Os outros dados devem ser bem claros: a data da violação, quando foi adicionada ao sistema, o número de contas pwned, a descrição da violação (novamente, isso pode mudar se o palavreado precisar ser ajustado) e & # x201C; DataClasses & # x201D ;. Uma das coisas que muitas pessoas estavam pedindo era uma descrição do que estava comprometido na brecha, então agora há um monte de atributos que podem ser adicionados através de uma coleção sobre a violação em si. Eu já estou mostrando isso abaixo de cada violação na página de sites da Pwned (essa é outra razão pela qual eu posso agora ajustar algumas das descrições).
Esta é uma mudança urgente. Enquanto o sentimento da API é o mesmo & # x2013; forneça um nome de conta, receba de volta uma lista de violações & # x2013; não há mais uma matriz de strings de nomes de violações. Se eu simplesmente substituísse a API antiga por essa, as coisas iriam quebrar. APIs. Devo. Evoluir.
O software evolui, as APIs devem ser versionadas.
Vamos ser sinceros sobre isso: o mundo segue em frente. A API para o HIBP durou cerca de 2 meses, não porque foi mal projetada, mas porque o serviço se tornou insano e inesperadamente bem-sucedido. Eu gosto desse tipo de problema, e você também deveria.
Agora eu tive uma escolha; ou eu poderia me contentar com o que eu tinha e privar as pessoas de uma maneira melhor, eu poderia adicionar ao serviço existente de uma forma não violenta ou eu poderia criar uma nova versão (embora expondo a mesma entidade de uma maneira diferente) e construir É a melhor maneira de saber como; sem bytes desnecessários, modelados corretamente (até que eu decida que uma nova versão é mais correta) e uma boa representação da entidade que eu estou tentando finalmente entrar nos consumidores & # x2019; apps.
Não há nada de errado em introduzir uma nova versão de uma API quando é a coisa mais sensata a ser feita. Por todos os meios, faça o seu melhor para obtê-lo & # x201C; direita & # x201D; desde o primeiro dia, mas fazê-lo com a expectativa de que "certo" & # x201D; é um estado temporário. É por isso que precisamos estar aptos para a versão.
Os vários campos de versionamento.
Certo, então quão difícil pode ser esse negócio de versionamento? Quero dizer, deve ser um exercício simples, certo? O problema é que isso é muito filosófico, mas em vez de ficar atolado nisso por enquanto, deixe-me delinear as três escolas comuns de pensamento em termos de como elas são praticamente implementadas:
URL: basta digitar a versão da API no URL, por exemplo: haveibeenpwned / api / v2 / breachedaccount / foo Cabeçalho de solicitação personalizada: você usa o mesmo URL de antes, mas adiciona um cabeçalho como & # x201C; api-version: 2 & # x201D; Aceitar cabeçalho: você modifica o cabeçalho de aceitação para especificar a versão, por exemplo, & # x201C; Accept: application / vnd. haveibeenpwned. v2 + json & # x201D;
Tem havido muitas, muitas coisas escritas sobre isso e eu vou linkar para eles no final do post, mas aqui está a versão abreviada:
Os URLs são uma droga porque devem representar a entidade: na verdade, eu concordo com isso na medida em que a entidade que estou recuperando é uma conta violada, não uma versão da conta violada. Semanticamente, não é realmente correto, mas é fácil de usar! Cabeçalhos de pedidos personalizados são uma droga porque não é realmente uma forma semântica de descrever o recurso: A especificação HTTP nos dá um meio de solicitar a natureza que gostaríamos do recurso representado por meio do cabeçalho de aceitação, por que reproduzir? esta? Aceitar cabeçalhos chupados porque são mais difíceis de testar: não posso mais apenas fornecer a alguém um URL e dizer: "##201C; aqui, clique em" & # x201D ;, em vez disso, eles devem construir cuidadosamente a solicitação e configurar o cabeçalho de aceitação adequadamente .
Os vários argumentos a favor e contra cada abordagem tendem a ir de & # x201C; este é o & # x2018; certo & # x2019; maneira de fazer isso, mas é menos prático & # x201D; através de & # x201C; Esta é a maneira mais fácil de criar algo consumível que, portanto, faz com que seja "# & # x2018; right & # x2019; & # x201D ;. Há muita discussão sobre hipermídia, negociação de conteúdo, o que é & nbsp; REST & # x201D; e todo tipo de outras questões. Infelizmente, isso muitas vezes é filosófico e perde a visão de qual deve ser o objetivo real: construir um software que funcione e particularmente para uma API, tornando-a facilmente consumível.
É sobre ter um contrato estável, estúpido!
Mais importante do que todas as reclamações e delírios sobre como fazer isso dessa maneira ou daquela maneira é dar estabilidade às pessoas. Se eles investem seu esforço suado escrevendo código para consumir sua API, então é melhor que você não a interrompa mais adiante.
Honestamente, os debates sobre o que é o & # X201C; RESTful & # x201D; contra o que não é como se o próprio termo ditasse seu sucesso é apenas louco. Transforme essa discussão em "Aqui estão as razões práticas pelas quais isso faz sentido e isso é o que pode acontecer se você não o fizer", e eu farei de tudo. O problema é que até mesmo as vozes da razão dentro das discussões barulhentas deixam dúvidas quanto ao que realmente é a melhor abordagem e, portanto, eu alcancei um compromisso & # x2026;
Aqui estão 3 maneiras erradas de consumir a API de HIBP que você pode escolher agora.
Ok, agora que estamos claramente estabelecidos, mas você está errado, eu gostaria de dar a você a opção de escolher qualquer uma das três formas erradas. Espere & # x2013; o que?! É assim: no entanto, eu implemento a API, ela será muito difícil de consumir, muito acadêmica, muito provavelmente falha no proxy ou algo do tipo. Em vez de escolher um caminho errado, decidi dar-lhe todas as três formas erradas e você pode escolher o que é o menos errado para você.
Caminho errado 2 - cabeçalho de solicitação personalizada:
Inevitavelmente, alguém vai me dizer que fornecer 3 formas erradas é a coisa errada a fazer. Não significaria mais código kludge para manter? Não, isso significa simplesmente que a implementação da API da Web subjacente é decorada com dois atributos:
O primeiro é simplesmente uma restrição de roteamento que implementa o RouteFactoryAttribute. Eu passo na rota e passo a versão que pode mapear para aquela rota, então a implementação procura a presença de um & # x201C; api-version & # x201D; cabeçalho ou um cabeçalho de aceitação correspondente a esse padrão:
Se a versão especificada em uma dessas combina com a especificada na restrição de roteamento, então, é o método que será invocado. Esta é uma adaptação simples desta amostra no CodePlex.
O segundo atributo que decora o método GetV2 acima é cortesia da Web API 2 e do recurso de roteamento de atributos. É claro que sempre poderíamos fazer roteamento na API da Web, mas isso geralmente era definido globalmente. O roteamento de atributos como esse traz a definição de rota para o contexto em que ela é aplicada e facilita a visualização da ação do controlador que será chamada por qual rota. Isso também significa que as implementações de todas as três formas erradas de chamar a API estão reunidas em um único local.
Então, em suma, não, isso não cria um monte de kludge e é muito fácil de manter. Cada uma das três abordagens retornará exatamente o mesmo resultado e, o mais importante, elas permanecerão estáveis ​​e não serão alteradas de nenhuma forma e, no final das contas, será a mais importante. importante, independentemente de qual opção você escolher. Toda a implementação agora também está claramente documentada na página da API do site.
Mas e se você não especificar uma versão?
Você sabe o pouco onde eu disse que você não pode quebrar o que já está lá fora? Sim, isso significa que se você fizer o que faz agora, # x2013; não especifique uma versão & # x2013; então você começa o que você recebe agora. Em outras palavras, nenhum pedido para uma versão específica significa que você obtém a versão 1.
Estou bem com isso, independentemente de ter atingido este ponto por padrão. Eu sei que algumas pessoas sempre gostam de retornar a versão mais recente se um número não for especificado, mas IMHO que quebra todo o contrato estável & # x201; & # x201D; objetivo; o que você obtém da API hoje pode ser completamente diferente do que você recebe amanhã se eu revisá-lo. Isso seria uma droga e quebraria as coisas.
Você tem 3 opções, mas minha preferência pessoal é & # x2026;
Eu tenho o luxo de controlar tanto a API quanto o consumidor primário dela, sendo o próprio site de HIBP. Dado que eu forneci 3 opções para consumir a API, qual delas eu mesmo uso?
Eu fui com o favorito filosófico que é especificá-lo através do cabeçalho de aceitação. Eu não acho que isso é certo e os outros estão errados, ao contrário, eu acho que isso faz mais sentido por duas razões principais:
Concordo que o URL não deve mudar: se concordarmos que o URL representa o recurso, a menos que estejamos tentando representar versões diferentes do próprio recurso, não, não acredito que o URL deva mudar. As brechas para foo são sempre as brechas para foo e eu não acho que só porque eu mudo os dados retornados para foo que a localização de foo deve mudar. Concordo que os cabeçalhos de aceitação descrevem como você deseja os dados: Esta é uma semântica da especificação de HTTP e assim como a semântica dos verbos de solicitação faz muito sentido (isto é, estamos obtendo ou colocando ou excluindo ou postando), O mesmo acontece com a maneira como o cliente gostaria que o conteúdo fosse representado.
De maneira nenhuma isso significa que eu acho que os outros dois estão errados e, francamente, não há melhor maneira de compartilhar a API com alguém do que dizer: "Aqui, clique aqui", mas quando eu puder facilmente construir o pedido e gerenciar os cabeçalhos, eu fui com esta rota.
Na verdade, pensando nisso, eu também uso a versão na rota do domínio. Por quê? Apenas através do processo de escrever esta API eu estava constantemente me comunicando com as pessoas sobre as formas de consultá-las (mais sobre isso mais tarde) e os atributos que ela retorna. Ser capaz de passar por um e-mail e dizer "Ei, aqui está o que eu estou pensando" ############################################################### e eles simplesmente clicam e obtêm resultados é inestimável. Esse é o ponto que os proponentes da abordagem de versionamento de URL fazem com razão: você simplesmente não pode fazer isso quando estiver dependente de cabeçalhos.
Ah, e no caso de você estar me checando, no momento em que escrevo, eu ainda não rolei o site para a v2 da API. Agora que os dados de violação são extraídos na API quando ocorre uma pesquisa, isso significa que eu tenho o luxo de não carregar todas as violações na origem na carga inicial (isso nunca será sustentável à medida que o conjunto de dados se expande). Isso salvará um monte de tráfego de saída e acelerará as coisas para as pessoas em termos de obter o site carregado, mas isso também significa um pouco mais de trabalho do meu jeito. Fique ligado.
No fechamento.
Claramente, eu tenho sido um pouco irônico aqui com relação a tudo estar errado, mas honestamente, quanto mais você lê sobre isso e quanto mais perguntas você faz, mais errado todo caminho parece de uma maneira ou de outra. Na verdade, eu sei muito bem que existem aspectos da minha implementação que serão referidos como "errados" e "x201D". (Eu posso pensar em pelo menos um par) e, naturalmente, eu estou me preparando para o potencial ataque de feedback para esse efeito. A coisa é, porém, cada uma dessas opções funciona e, francamente, para todos os efeitos práticos, eles funcionam tão bem quanto os outros.
Se eu puder deixar outras pessoas pensando em como atualizar suas APIs com um pensamento final: ninguém usará sua API até que você a tenha criado. Pare de procrastinar. Nenhuma dessas opções é "ruim", "# x201C; ruim & # x201D; em qualquer sentido tangível, eles são apenas diferentes. Eles são todos facilmente consumíveis, todos eles retornam o mesmo resultado e nenhum deles é susceptível de ter qualquer impacto real sobre o sucesso do seu projeto.
Referências.
Stack Overflow: Práticas recomendadas para o versionamento de API? (ótima pergunta, ótimas respostas, fechada como "não construtiva", eu assumo porque "Bill the Lizard & # x201D; saiu do lado errado da cama naquela manhã) Blog do Lexical Scope: How are REST APIs com versão? (boa comparação de práticas de controle de versão entre serviços, ainda que alguns anos atrás) CodePlex: Exemplo de restrição de roteamento (vinculado na página da API da Web da Microsoft como um exemplo de APIs de controle de versão adicionando um cabeçalho personalizado) CodeBetter: Versionamento RESTful Serviços (muito pragmáticos e uma boa descrição das várias maneiras pelas quais uma API pode mudar) Blog de Vinay Sahni: Práticas recomendadas para projetar uma API RESTful pragmática (ele está argumentando sobre o versionamento de URL por causa de & # x201C ; explorabilidade do navegador & # x201D;) Lans Pivotal: versionamento da API (boa visão das opiniões conflitantes existentes) Pilha Web de Amor: ASP. NET Web API Versioning com Tipos de Mídia (bom passo-a-passo de criar um aplicativo para suportar versioning by content negotiation)
Hi, I'm Troy Hunt, I write this blog, create courses for Pluralsight and am a Microsoft Regional Director and MVP who travels the world speaking at events and training technology professionals.
Hi, I'm Troy Hunt, I write this blog, create courses for Pluralsight and am a Microsoft Regional Director and MVP who travels the world speaking at events and training technology professionals.
Upcoming Events.
I usually run private workshops around these, here's the upcoming public events I'll be at:

Api versioning strategy


This is a good and a tricky question. The topic of URI design is at the same time the most prominent part of a REST API and , therefore, a potentially long-term commitment towards the users of that API .
Since evolution of an application and, to a lesser extent, its API is a fact of life and that it's even similar to the evolution of a seemingly complex product like a programming language, the URI design should have less natural constraints and it should be preserved over time . The longer the application's and API's lifespan, the greater the commitment to the users of the application and API.
On the other hand, another fact of life is that it is hard to foresee all the resources and their aspects that would be consumed through the API. Luckily, it is not necessary to design the entire API which will be used until Apocalypse. It is sufficient to correctly define all the resource end-points and the addressing scheme of every resource and resource instance.
Over time you may need to add new resources and new attributes to each particular resource, but the method that API users follow to access a particular resources should not change once a resource addressing scheme becomes public and therefore final.
This method applies to HTTP verb semantics (e. g. PUT should always update/replace) and HTTP status codes that are supported in earlier API versions (they should continue to work so that API clients that have worked without human intervention should be able to continue to work like that).
Furthermore, since embedding of API version into the URI would disrupt the concept of hypermedia as the engine of application state (stated in Roy T. Fieldings PhD dissertation) by having a resource address/URI that would change over time, I would conclude that API versions should not be kept in resource URIs for a long time meaning that resource URIs that API users can depend on should be permalinks .
Sure, it is possible to embed API version in base URI but only for reasonable and restricted uses like debugging a API client that works with the the new API version. Such versioned APIs should be time-limited and available to limited groups of API users (like during closed betas) only. Otherwise, you commit yourself where you shouldn't.
A couple of thoughts regarding maintenance of API versions that have expiration date on them. All programming platforms/languages commonly used to implement web services (Java,.NET, PHP, Perl, Rails, etc.) allow easy binding of web service end-point(s) to a base URI. This way it's easy to gather and keep a collection of files/classes/methods separate across different API versions .
From the API users POV, it's also easier to work with and bind to a particular API version when it's this obvious but only for limited time, i. e. during development.
From the API maintainer's POV, it's easier to maintain different API versions in parallel by using source control systems that predominantly work on files as the smallest unit of (source code) versioning.
However, with API versions clearly visible in URI there's a caveat: one might also object this approach since API history becomes visible/aparent in the URI design and therefore is prone to changes over time which goes against the guidelines of REST. Concordo!
The way to go around this reasonable objection, is to implement the latest API version under versionless API base URI. In this case, API client developers can choose to either:
develop against the latest one (committing themselves to maintain the application protecting it from eventual API changes that might break their badly designed API client ).
bind to a specific version of the API (which becomes apparent) but only for a limited time.
For example, if API v3.0 is the latest API version, the following two should be aliases (i. e. behave identically to all API requests):
In addition, API clients that still try to point to the old API should be informed to use the latest previous API version, if the API version they're using is obsolete or not supported anymore . So accessing any of the obsolete URIs like these:
should return any of the 30x HTTP status codes that indicate redirection that are used in conjunction with Location HTTP header that redirects to the appropriate version of resource URI which remain to be this one:
There are at least two redirection HTTP status codes that are appropriate for API versioning scenarios:
301 Moved permanently indicating that the resource with a requested URI is moved permanently to another URI (which should be a resource instance permalink that does not contain API version info). This status code can be used to indicate an obsolete/unsupported API version, informing API client that a versioned resource URI been replaced by a resource permalink .

REST APIs don’t need a versioning strategy – they need a change strategy.
Change in an API is inevitable as your knowledge and experience of a system improves. Managing the impact of this change can be quite a challenge when it threatens to break existing client integrations.
Developers often try to decide on a versioning strategy as soon as they start work on an API. This is understandable but it’s not always the smartest way of looking at the problem of managing change. Brandon Byers summed this up by borrowing Jamie Zawinski’s dig at regular expressions:
Some people, when confronted with a problem, think “I know, I’ll use versioning.” Now they have 2.1.0 problems.
How can you version resources in REST?
REST doesn’t provide for any specific versioning but the more commonly used approaches fall into three camps: putting it on the URI, using a custom request header or a adding it to the HTTP Accept header.
Using the URI is the most straightforward approach though it does upset REST advocates who insist that a URI should refer to a unique resource. You are also guaranteed to break client integrations when a version is updated no matter how heavily you invest in creative routing and client communication.
A custom header allows you to preserve your URIs between versions though it is effectively a duplicate of the content negotiation behaviour implemented by the existing Accept header. A client can use this header to send a list of supported versions while the server responds with the version used in the Content-Type header.
Content negotiation may let you to preserve a clean set of URLs but you still have to deal with the complexity of serving different versions of content somewhere . This burden tends to be moved up the stack to your API controllers which become responsible for figuring out which version of a resource to send. The end result tends to be a more complex API as clients have to know which headers to specify before requesting a resource.
The version number isn’t the problem.
Given the contentious nature of REST, you’ll always be wrong in somebody’s eyes no matter what approach you take. The point is that version numbering itself is a red herring.
The real challenge here is in managing a code base that can serve up multiple versions of resources. If you keep all versions in the same code base then older versions become vulnerable to unexpected changes. If you separate the code bases then the operational and support overhead escalates. In both cases, code bloat and increased complexity are an inevitable consequence.
A strict approach to versioning does give you much-needed certainty over the contract but it does tend to undermine a system’s capacity to change . Versioning can become a barrier to improvement as any requirements that lead to version changes are resisted. I have seen APIs with strict versioning policies stuck on the same version for years due to legitimate concerns over the amount of work and risk involved in change.
What’s the alternative to versioning?
A coherent version strategy should address how you will manage change in your API whilst providing a stable contract to clients. This doesn’t have to include issuing new versions in response to changes.
One approach is to build in the possibility of change by making provision for backwards compatibility in API changes. This approach does carry significant risk as you cannot be sure that a change will not break existing clients even with exhaustive regression testing.
You can even take backwards compatibility a step further by adding features such as optional parameters and wildcard properties that anticipate future changes. This kind of “ forwards compatibility ” tends to produce a coarse contract that places a considerable burden of validation onto the client. The end result is often a messy set of switches and codes required for each call.
Bertrand Meyer’s Open\Closed principle suggests that software entities should be “open for extension, but closed for modification”. When applied to APIs the implication is that you can augment your resources but not change them.
This approach could offer the certainty of stricter versioning without the regression risks involved in backwards compatibility. Augmentation is not without its problems though as it can give rise to bloated contracts. Without careful discipline an API can become littered with duplicate methods or resources that provide several slightly different ways of achieving the same thing.
Can you share the responsibility?
You could do more to share the burden of change between API and client. Postel’s law, often referred to as the Robustness principle, states that you should be “liberal in what you accept and conservative in what you send”. In terms of APIs this implies a certain tolerance in consuming services.
For example, strict serialization techniques can be unnecessarily intolerant of change. A more tolerant reader should only be concerned with data that it needs and ignore every other part of the response. This means that the majority of changes are unlikely to break the integration.
Another approach could be for the consumer to declare the data they are interested in as part of a request. This consumer-driven contract pattern does not specify the form that these consumer assertions should take, but an implementation could allow an API to detect when a request is out of date.
Unfortunately, these approaches can only be applied to relatively closed communities of services. Public-facing APIs rarely have the luxury of being able to dictate the style of client integration. The only enforceable contract you have between service and client is made up of the data and protocol.
This is why careful discipline is at the heart of any sensible change strategy. A good API doesn’t come into being by accident. It has to be curated . Whatever approach you take to managing change you will need consistent and active governance over the evolving contract.
I am a London-based technical architect who has spent more than twenty years leading development across start-ups, digital agencies, software houses and corporates. Over the years I have built a lot of stuff including web sites and services, multi-screen applications, systems integrations and middleware.
My current focus is on enabling scalable SaaS delivery and providing architectural leadership in agile environments. I currently work for SaaS provider Fourth leading them to enterprise heaven, one service at a time.
You can follow me on Twitter or check me out on LinkedIn.
Microservice preconditions: what needs to be in place before you decompose that monolith…
One of the main benefits of microservices is that they reduce the cost of change. The problem is that you need to make a significant up-front investment to realise this saving. Your first few microservices are more likely to be an expensive and potentially painful undertaking.
relaxar. There’s no conflict between architecture and agile.
Agile teams still need to make architecture decisions, but in supporting them architects should seek “just enough” architecture over “big design up front” and practical solutions over large-scale abstract thinking.
Automating Docker image deployments using Azure Container Instances.
Azure’s Container Instances provides an easy and quick way to run Docker images without having to learn the various complexities of orchestration platforms such as Kubernetes.
Can TOGAF and Agile really go together?
On the face of it, TOGAF describes a very different world to the agile preference for working software over documentation. That doesn’t mean that TOGAF is incompatible with agile, so long as you’re prepared to adapt its numerous building blocks.
Entity services: when microservices are worse than monoliths.
Finely-grained, entity-based services seem to be advocated by some pretty authoritative sources. This is unfortunate as they are something of an anti-pattern that can undermine many of the benefits of decomposing an monolith into micoservices.
Technical debt is an overused and lazy metaphor.
Technical debt may be a useful metaphor for describing how bad code design undermines productivity to non-technical audiences, but it does not help in understanding the longer term problems that affect code bases.
Events, sagas and workflows: managing long-running processes between services.
An event-driven architecture can give rise to complex chains of events that are difficult to manage. These problems can be mitigated through careful design rather than resorting to shared state databases or workflow engines.
What should a Scaled Agile “architectural runway” actually look like?
The Scaled Agile Framework talks about an “architectural runway” as the main deliverable for agile architecture, yet it’s vague on the detail of what this looks like.

Комментариев нет:

Отправить комментарий