Wednesday, 14 March 2018

Estratégia de versão do restante api


Formas de versão de sua API, Parte 2.


Esta é parte dois de uma série no controle de versão da API. A Parte Um abrangia os métodos prevalecentes para a versão de sua API e permitindo que os clientes codificassem em uma versão especificamente. Eu sugiro que você leia essa publicação (pelo menos descreva a introdução!) Antes disso, pois fornece algum contexto necessário. Nele, sugeri um outro método que utiliza alguns conceitos pouco conhecidos das especificações do cabeçalho de Aceitação, que pode permitir que você faça uma API sem versão. Eu admitirei bem na frente, no entanto, é um pouco equivocado, mas acho que é importante. Você ainda pode editar as coisas na API, mas você não pode controlar a própria interface. Você está simplesmente a controlar as representações de recursos.


A alteração mais comum em qualquer API REST arquitetada é adicionar, alterar ou remover campos dos recursos. Novas informações são adicionadas ou podem estar em um formato diferente. As informações podem ficar indisponíveis. Você também pode adicionar, mover ou remover recursos. Dependendo da sua arquitetura API, os verbos HTTP podem significar coisas ligeiramente diferentes. Todos esses normalmente exigiriam um incremento da versão da API se eles causassem que os aplicativos existentes se quebrassem. Com um pouco de previsão, no entanto, sua API pode mudar sem exigir uma estratégia de controle de API completa.


Arquiteto uma interface sem versão:


Use esquemas de URI sãos: / api / collection_name / resource_id Siga as definições de métodos HTTP A adição de recursos deve sempre ser compatível com versões anteriores A remoção de recursos deveria ser feita através de versões de qualquer maneira. Os recursos móveis podem ser gerenciados por redirecionar códigos HTTP.


Representações de recursos de versão:


Use o cabeçalho de Aceitação 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 através de versões de qualquer maneira. As informações de mudança podem ser feitas com Aceitação de versão.


Arquitetando uma API sem versão.


Deixe-me começar por dizer que eu reconheço que uma API sem versão é um pouco de um estado ideal, e uma API com uma estratégia de controle de versões bem pensada é muito preferível a uma API com uma tentativa mal pensada de não versão. Não há vergonha em dizer que você acha que precisa do controle de versão, nem que todas as APIs possíveis se encaixam nessa estratégia sem versão. Isso realmente funciona apenas para as APIs baseadas em manipulação de recursos com REST, que se seguem aos padrões vigentes. Dito isto, uma grande quantidade de APIs pode ser retrabalhada para se encaixar nesse estilo. Além disso, isso é destinado a APIs back-end, e não interfaces de interface com seu front-end na web. Na minha opinião, estas devem ser quase sempre APIs separadas para que você possa atualizar a funcionalidade de front-end da Web em seu próprio ritmo sem se preocupar com nenhum usuário da API. Eu sei que eu pessoalmente sou muito mais relaxado no meu seguimento de padrões para APIs front-end.


O primeiro passo para entender como criar uma API sem versão é saber que você não deseja versão da própria interface. Isso significa que você não quer mudar como e onde as informações são armazenadas e acessadas. Em termos práticos, esta é a estrutura URI. Mesmo esta regra pode ser dobrada, é claro - construída diretamente na especificação HTTP são redirecionamentos! Se você moviu informações, simplesmente forneça um redirecionamento permanente para o novo URI. Agora, o que acontece se você remover um recurso?


Os dois motivos por que um URI particular pode ser removido de uma API típica: ou o próprio tipo de recurso foi removido, ou mais comumente, que a representação particular do recurso não é mais suportada. No último caso, você realmente não aderiu à arquitetura REST: a representação do recurso deve ser desacoplada do URI. No caso anterior, se o tipo de recurso inteiro já não estiver acessível, é provavelmente por uma razão comercial, caso em que você deseja removê-lo de todas as versões anteriores da API também. Nesse caso, o controle de versão não conseguiu realmente nada, não é?


Adicionar recursos, ou informações aos recursos, sempre deve ser uma mudança compatível com versões anteriores. Se você estiver usando o JSON, adicionar elementos aos recursos existentes deve ser uma brisa. Mesmo que você tenha 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 versões sem alterações é o que acontece quando você executa um método específico em uma determinada API. Por exemplo, se você pudesse POST para / api / foo / e crie um novo recurso foo para você, mas agora você deseja que ele edite um recurso foo existente. O melhor que posso dizer é que não, em vez disso, siga as definições recomendadas do método de especificação HTTP explicitamente:


GET / api / foo / ou GET / api / foo / 1 recupera recursos ou 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 são campos de atualizações idempotentes PATCH / api / foo / 1 (padrão proposto) 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 o DELETE deve notificar de alguma forma se o recurso não existisse em primeiro lugar e uma maneira apropriada de fazer isso seria um erro, mas eu vou adiar nisso. OPTIONS e HEAD são usados ​​menos e se você estiver usando eles, você provavelmente sabe o que você está fazendo de qualquer maneira. Se você estiver usando PATCH, esteja ciente de que não é um padrão bem suportado, e muitas API aceitarão pedidos PUT incompletos e somente atualizarão os campos alterados. Eu acho que isso está bem, desde que seja um comportamento bem compreensivo e documentado, com suporte PATCH manchado, pelo menos até que seja mais aceitável.


Muitas vezes, os recursos são modificados pelos pedidos POST. Um formulário envia, você interpreta os dados e muda um recurso. Este é um padrão comum em APIs de front-end, e como eu mencionei acima, isso é bom. Não é perfeito, mas bom. Em uma API de back-end, isso não deve acontecer! Use uma solicitação PUT ou PATCH e defina explicitamente o que deseja que o novo recurso seja. Uma desculpa comum é as versões antigas do IE don & # 8217; t suporte PUT ou PATCH, mas esta é uma API de back-end, ela é boa! Todas as principais bibliotecas que conheço pelo menos suportam PUT - se você estiver usando um que não tenha, provavelmente você deve procurar em outro lugar.


Em suma, um pré-requisito para a inexatidão é que todos os recursos que você deve poder ser acessados ​​e manipulados em um fasion consistente, sendo as únicas diretivas 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árias URIs, você provavelmente encontrará situações em que você precisa para a versão.


Versão de representações de recursos.


Como mencionei na introdução, as próprias representações de recursos transferidas para o cliente podem e provavelmente devem ser controladas. A beleza desta abordagem é que cada recurso pode ser versionado de forma independente. Se você mudar um recurso, um mês depois, você decide mudar um recurso diferente, você não precisará aumentar um contador de versão da API duas vezes. Cada versão do recurso é incrementada individualmente. Note-se que não estou falando sobre a versão dos próprios recursos, apenas a representação do recurso. Se você tiver um recurso versionado, por exemplo, um documento que tenha revisões anteriores disponíveis, estes devem ser acessados ​​separadamente do método I & # 8217; descrevendo aqui.


Familiarizar-se com a especificação de cabeçalho Accept provavelmente irá ajudá-lo a entender a verdadeira profundidade de quão longe as especificações podem ir para a prova de futuro. Quase todo mundo sabe que o cabeçalho Aceita especifica o tipo de MIME-Type que o solicitante espera, como application / json. Menos sabe que não pode apenas especificar um tipo, mas pode especificar vários tipos aceitáveis, bem como parâmetros em cada tipo. Para representar recursos de versão, nós iremos aproveitar os parâmetros de tipo.


I & # 8217; ll entrar e você considerou o seguinte:


Mesmo sem entender completamente o cabeçalho Aceites, você provavelmente pode adivinhar que essa seqüência de caracteres implica que ela espera que o aplicativo / vnd. example. foo digite o formato json, a versão 2, se disponível, e qualquer versão do contrário. Analisar o cabeçalho Aceitar de uma maneira consistente com as especificações pode ser difícil apenas porque muitas bibliotecas não analisam a caixa.


Então, quando você deve representar recursos de versão? Como mencionei acima, se você estiver removendo informações sobre um recurso, é provavelmente por uma razão comercial que você não quer mais exposto. Na era da transmissão comprimida de hoje, há pouco ganho para tirar da informação simplesmente porque você não sente mais útil. A adição de informações sempre deve ser possível de forma compatível com versões anteriores. Você pode querer versão em caso de alterar o nome e / ou o tipo de um campo, por exemplo, se você quiser (tempo de exemplo do mundo real!), Repurpose um campo booleano com o & # 8220; habilitado & # 8221; para um status mais genérico & # 8220; & # 8221; tipo de enum.


Agora, como faço isso?


Infelizmente, muito do que eu discuti aqui tem pouco ou nenhum suporte amplo na comunidade de pessoas que realmente criam API amplamente utilizadas. Eu suspeito que nenhuma parte pequena disso é devido à dificuldade em implementá-los em uma aplicação do mundo real. Dependendo da sua plataforma, pode ser fácil ou difícil, e poucas bibliotecas suportarão uma estratégia de controle como esta fora da caixa. O mais próximo que eu sei é o nó de resposição que suporta roteamento versionado com base em um cabeçalho de versão de aceitação.


Eu irei a passar por algumas bibliotecas e tentando estendê-las para suportar o controle de versão no futuro. Possivelmente tentando minha própria biblioteca que assa muito isso gratuitamente. Quanto mais fácil é para um desenvolvedor escrever código compatível com padrões, mais provável eles vão adotá-lo, porque, no final, se se resume à facilidade de desenvolvimento versus adesão aos padrões, acho que todos sabemos que a facilidade ganhará a cada vez .


RESTFul API Versioning Insights.


No que diz respeito ao controle de API, existem muitas práticas recomendadas e informações, mas ainda não há uma sólida prática sólida.


Para entender a versão do Restful API, primeiro precisamos entender o problema.


O Problema de Versões.


Não é possível quebrar seus clientes.


Alterar sua API é uma coisa bastante fundamental para fazer. Você está mudando literalmente a interface com a qual os clientes se comunicaram antes da mudança. O fato é que você não quer quebrar os clientes que se conectam a você hoje, enquanto ainda precisam alterar (adicionar, remover ou alterar) sua API. Isso não afeta apenas o que a API parece, ou seja, os formatos de solicitação ou resposta também podem incluir funcionalidade, e. os padrões agora funcionam de forma diferente.


Infelizmente, não importa o quão brilhantemente você arquiteta sua solução, você pode achar que, ao longo do tempo, você deve mudá-la.


Pode-se argumentar que os micro-serviços contornam esse problema ao serem pequenos. Os micro-serviços devem ser tão pequenos que são tão simples que você não terá espaço para mudá-los - você pode ler mais sobre o que são micro-serviços, mas não vou falar sobre eles hoje.


Então, supondo que você precise alterar sua API, o que você realmente quer fazer é garantir que seus clientes saibam que a sua API mudou e dê-lhes alguma maneira de decidir, ou de outra forma, a forma de programação, a que versão eles vão se conectar que eles continuam trabalhando.


Agora que entendemos o problema, quais são as soluções possíveis?


As 4 Possíveis Soluções para a Versão da API.


Antes de eu dizer mais, gostaria de indicar que cada opção tem seus prós e contras particulares. O que você acaba escolhendo pode ser afetado não só pelas melhores práticas, restrições da infra-estrutura e outros aspectos. Atualmente, não existe a melhor solução para o Restful API Versioning e há mesmo aqueles que acreditam que não devemos precisar nossas APIs como esta publicação "Do not Version Your Web API" por Jan Stenberg.


Neste método, a versão é explicitamente colocada no URI da API. Por exemplo:


. / mapas / versão / 2. / mapas / versão / 2 / edifícios / versão / 3. / mapas / v2 / edifícios.


As opções acima mostram três formas diferentes de expor versões através do URI;


Em primeiro lugar, um modelo inteiro de hierarquia de grãos grosseiros e, em seguida, um método de sub-tópico mais refinado que nos permite a versão elementos separados da API (estradas neste caso). A terceira opção apenas mostra o modelo ligeiramente menos expressivo de ter um argumento de versão única (por exemplo, 'v2') sem o nó da versão explícita na hierarquia de URL.


Eu, pessoalmente, não gosto desse modelo. Do ponto de vista mais puro, argumenta-se que a URI em REST deve representar apenas a estrutura de recursos.


Uma versão não é um recurso, é um atributo do recurso.


No entanto, em um lado positivo, posso ver como é muito claro o que está acontecendo! Eu também vejo isso sendo recomendado por muitos fornecedores de ferramentas API. Aqui estão alguns prós e contras para esse método específico.


Já podemos ver como as vantagens para uma pessoa podem ser vistas como desvantagens para outra.


URIs sugam porque devem representar a entidade - Eu quero recuperar a entidade de mapas, não uma versão da conta quebrada. Semanticamente, não é realmente correto, mas é muito fácil de usar!


2) O cabeçalho de aceitação.


Existe um conhecido cabeçalho HTTP chamado Aceitar, que é enviado em uma solicitação de um cliente para um servidor. Por exemplo.


Esta notação está dizendo que eu, o cliente, gostaria que a resposta fosse no json, por favor.


Os cabeçalhos de aceitação estão usando este cabeçalho para criar seus próprios tipos de recursos, por exemplo:


Aceite: application / vnd. myapi. v2 + json.


Agora; Aguarde aqui porque essa é uma sintaxe um pouco estranha que nos encontramos olhando, então vamos passar por isso.


As especificações da internet dizem que eu, como fornecedor, pode definir (e ter que registrar) um tipo de mídia. Se eu fizer isso, chama-se (sem surpresa) um tipo de mídia "fornecedor". Eu deveria prefixar meu tipo com 'vnd' para deixar claro que é minha própria definição. Eu então preciso dizer qual é o nome do tipo real que eu estou definindo, p. 'myapi'. No entanto, a especificação não indica nada sobre um número de versão para que as pessoas tenham adotado para dizer que seu nome de tipo de mídia inclui um número de versão, por exemplo:


Agora, porque eu, como aplicativo cliente, ainda preciso definir o tipo de conteúdo que eu realmente quero (além da versão), isso pode ser adicionado como um sufixo ao tipo de mídia solicitado, e. '+ json' neste caso.


Observe que existe um método alternativo para fazer isso sem qualquer pré-registro do tipo de mídia usando x. como o prefixo:


O uso do cabeçalho Accept se parece com um corte muito pequeno da especificação para mim - mas funciona e é bem conhecido, se não for totalmente especificado como tal.


O maior problema com este método é que está bastante escondido - e as coisas escondidas são sempre um pouco mais difíceis de trabalhar. É quase sempre melhor ser explícito no que você está fazendo. Eu também suspeito que pedir ao seu administrador de firewall para abrir seu firewall para qualquer tipo de mídia vnd antigo poderia levar a um risco de segurança bastante grande.


No entanto, parece que é muito mais fácil passar pelo cabeçalho Accept: vnd do que para passar por cabeçalhos de solicitação personalizados.


Aceite cabeçalhos sugam porque eles são mais difíceis de testar - eu não posso mais apenas dar a alguém um URL e dizer "Aqui, siga este link", em vez disso, eles devem construir cuidadosamente a solicitação e configurar o cabeçalho de aceitação apropriadamente.


3) Cabeçalho de pedido personalizado.


Nas especificações HTTP originais, você poderia definir qualquer cabeçalho HTTP antigo que você gostasse no seu pedido de cliente, desde que você tenha sido pré-fixado com 'X-', por exemplo,


As especificações mudaram e você ainda pode passar qualquer cabeçalho de solicitação antigo, mas não precisa ser pré-fixado com 'X-' mais, por exemplo,


Isso significa que você poderia pedir aos clientes de sua API para passar em algo como.


Esta opção não é recomendada nem usada demais devido às seguintes razões:


Alguns dos roteadores (embora hoje as coisas sejam diferentes e a maioria delas passará todos os cabeçalhos) pode rejeitar toda a solicitação HTTP ou simplesmente não passar o cabeçalho especial. Depurar isso pode ser uma coisa muito difícil de fazer. Eu tive a mudança para encontrar uma coisa em que algumas máquinas estavam se conectando através de roteadores diferentes e um roteador particular tinha sido configurado para remover tipos de cabeçalho não padrão. Permitiu a mensagem através - incluindo todos os outros cabeçalhos - mas apenas removia silenciosamente aqueles que não gostava!


Está escondido novamente - assim como o cabeçalho Aceitar. O cabeçalho Aceitar já é uma maneira de ser bastante explícito sobre o que o cliente aceita, então, se vamos esconder coisas, pelo menos, vamos usar uma maneira que é conhecida.


Os cabeçalhos de solicitação personalizados sugam porque não é realmente uma maneira 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 isso?


4) O parâmetro URI.


Aqui é óbvio que não vejo muitas pessoas usando:


Este método é altamente utilizado pela Amazon, Google e Netflix, mas ainda não é tão popular. Hmmm - talvez haja algo para isso ?!


Pensando no controle de versão do primeiro dia.


Com isso, quero dizer - quando você cria sua API real, acredita que isso irá mudar, mesmo que não hoje - algum dia. Isso afetará o que você codifica - não apenas suas decisões sobre onde colocar o número da versão.


Se você é um desenvolvedor ágil, então você poderia estar gritando na tela agora.


Agile é tudo sobre hoje. Na verdade, diz especificamente - não codifique coisas que não estão na especificação. No entanto, vamos ser claros: codificar a extensibilidade não é o mesmo que realmente colocar as extensões em si - a qual é a metodologia ágil.


Deixar espaço para futuras versões entra em ágil bem.


A versão de uma API é difícil!


Sim, é, no entanto, não é realmente difícil manter o código do cliente e do servidor em sincronia já foi. Você deve lembrar que o Building Restful APIs é muito mais fácil que os serviços da Web SOAP e é suportado praticamente por todos.


Tente permitir a extensibilidade em seu código no primeiro dia.


Com relação a como especificar a versão - Se você tiver uma convenção de controle de versão em mente, então certifique-se de que sua infraestrutura possa lidar com isso.


Leia mais postagens deste autor.


Compartilhe esta publicação.


Inscreva-se para REST API e Beyond.


Obtenha as últimas postagens enviadas diretamente para sua caixa de entrada.


ou assine via RSS com Feedly!


Orientações básicas da API RESTful.


Seu modelo de dados começou a se estabilizar e você está em condições de criar uma API pública para o seu & hellip;


REST API vs SOAP Web Services Management.


De volta ao dia, os Serviços da Web eram o padrão de fato para acessar "sistemas de registro". Serviços web SOAP e hellip;


O seu controle de versão da API é errado, razão pela qual eu decidi fazer 3 maneiras erradas diferentes.


No final, eu decidi que a maneira mais justa e equilibrada era irritar todos com igualdade. Claro que eu estou falando sobre o controle de versão da API e não desde o grande & # x201C; tabs versus spaces & # x201D; debate eu vi tantas crenças fortes em campos completamente diferentes.


Isso estava bem. Quando eu construí Eu fui escolhido? (HIBP) no final de novembro, pretendia 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 foi & # x201C; alguns & # x201D ;, de fato, no final da primeira semana, foi mais do que o Google Analytics poderia lidar. O objetivo é que você sempre pode prever o futuro quando você escreve sua API e, em algum momento, você pode precisar mudar algo em que as pessoas já dependem.


Mas aqui, o problema & # x2018; Toda vez que você começa a falar sobre qualquer coisa a ver com APIs por HTTP, isso acontece:


Todo o caminho em que você se transforma há diferentes pontos de vista filosóficos em & # x201C; o caminho certo & # x201D; e muito retroceder e avançar no REST, o que é RESTful, o que não é e se importa. Deixe uma conversa sobre as mudanças da API, o impacto no controle de versão, por que há tantas idéias divergentes sobre como deve ser feito e, em última análise, por que nenhuma das palavras é tão importante como realmente conseguir coisas feitas.


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 que criam tudo, desde aplicativos de smartphones até ferramentas de teste de penetração, a resposta acima funcionou bem no início, mas foi limitada. Por exemplo, essa resposta também não funciona bem:


Por quê? Porque & # x201C; BattlefieldHeroes & # x201D; é Pascal-encapsulado, o que é ótimo para combiná-lo com classes CSS codificadas (embora provavelmente não seja uma boa abordagem de longo prazo) e para ter um & # x201C; stable & # x201D; nome para se referir a (eu ganhei & # x2019; t mudá-lo, mesmo se houver uma segunda violação), mas não é adequado para exibição como título. Tudo isso sai do Azure Table Storage e depois entrei no SQL Azure para extrair dados relacionais que realmente descrevem a violação. Um dos atributos desse armazenamento relacional é o nome que você vê acima.


O que eu realmente queria fazer era algo mais parecido com isto:


Pegue? Para o ponto anterior sobre o nome da infração, esse ainda está lá no atributo de nome, mas agora temos um título também. Isto é o que você mostra para as pessoas & # x2018; & # x201C; Battlefield Heroes & # x201D; & # x2018; Mas, mais importante ainda, se Gawker for repetidamente, eu posso nomear a violação de algo como Gawker2017 e o título pode ser algo amigável ao longo das linhas de & # x201C; Gawker (Syrian Electronic Army Attack) & # x201D ;. Ele segmenta o que é estável e previsível a partir do que não é e significa que as pessoas podem criar dependências, como imagens ou outros recursos no atributo de nome.


Os outros dados devem ser bastante claros: a data da violação, quando foi adicionada ao sistema, o número de contas, a descrição da violação (novamente, isso pode mudar se a verbiagem precisa ser modificada) e & # x201C; DataClasses & # x201D ;. Uma das coisas que muitas pessoas pediram foi uma descrição do que foi comprometido na violação, 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á mostrando estes abaixo de cada violação na página dos sites Pwned (esta é outra razão pela qual agora posso ajustar algumas das descrições).


Esta é uma mudança radical. Embora o sentimento da API seja o mesmo & # x2018; fornecer um nome de conta, recuperar uma lista de violações & # x2018; não há mais um conjunto de caracteres de violação de nomes de violação. Se eu simplesmente substituísse a API antiga por essa, as coisas iriam quebrar. APIs. Devo. Evoluir.


O software evolui, as APIs devem ser controladas.


Deixe-se ficar claro sobre isso: o mundo continua. A API para o HIBP durou cerca de 2 meses, não porque estava mal concebida, mas porque o serviço tornou-se selvagem, inesperadamente bem sucedido. Eu gosto desse tipo de problema, e você também deveria.


Agora eu tinha 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 forma não rompente ou eu poderia criar uma nova versão (embora expondo a mesma entidade de uma maneira diferente) e construa da melhor maneira que eu sabia; 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 finalmente tentarei entrar nos consumidores & # x2019; aplicativos.


Não há nada de errado em apresentar uma nova versão de uma API quando é a coisa mais sensível. Por todos os meios, faça o seu mais difícil para obtê-lo & # x201C; right & # x201D; desde o primeiro dia, mas faça isso com a expectativa de que & # x201C; right & # x201D; é um estado temporário. É por isso que precisamos ser capazes de versão.


Os vários campos de versão.


Certo, então, como é difícil esse negócio de versão? Quero dizer, deve ser um exercício simples, certo? O problema é que ele é muito filosófico, mas, em vez de ficar atolado, por enquanto, deixe-me esboçar as três escolas comuns de pensamento em termos de como elas são praticamente implementadas:


URL: Você simplesmente bateu a versão da API no URL, por exemplo: haveibeenpwned / api / v2 / breachedaccount / foo Cabeçalho de solicitação personalizado: Você usa o mesmo URL que antes, mas adicione um cabeçalho como o & # x201C; api-version: 2 & # x201D; Aceitar cabeçalho: você modifica o cabeçalho de aceitação para especificar a versão, por exemplo & # x201C; Aceitar: application / vnd. haveibeenpwned. v2 + json & # x201D;


Houve muitas, muitas coisas escritas sobre isso e eu vou ligar para elas no final da publicação, mas aqui a versão abreviada é:


Os URLs sugam porque devem representar a entidade: na verdade eu realmente concordo com isso na medida em que a entidade I & # x2019; m recuperando é uma conta quebrada, e não uma versão da conta violada. Semanticamente, não é realmente correto, mas sim, é fácil de usar! Os cabeçalhos de solicitação personalizados sugam porque ele não é realmente uma maneira semântica de descrever o recurso: a especificação HTTP nos dá um meio de solicitar a natureza que nós gostamos do recurso representado por meio do cabeçalho de aceitação, por que reproduzir esta? Aceite cabeçalhos sugam porque eles são mais difíceis de testar: eu não posso mais apenas dar a alguém um URL e dizer & # x201C; Aqui, clique neste & # x201D; antes eles precisam construir cuidadosamente a solicitação e configurar o cabeçalho de aceitação adequadamente .


Os vários argumentos para e contra cada abordagem tendem a passar de & # x201C; Este é o & # x2018; right & # x2019; maneira de fazê-lo, mas é menos prático & # x201D; através de & # x201C; Esta é a maneira mais fácil de criar algo consumível o que, portanto, o torna & # x2018; direito & # x2019; & # x201D ;. Há muita discussão sobre hipermídia, negociação de conteúdo, o que é & # x201C; REST & # x201D; e todas as outras questões. Infelizmente, isso muitas vezes se torna filosófico e perde a visão do objetivo real: construir um software que funcione e particularmente para uma API, tornando-o facilmente consumível.


É sobre ter um contrato estável, estúpido!


Mais importante do que todo o desencadeamento e delírio sobre fazê-lo dessa maneira ou dessa forma é dar às pessoas estabilidade. Se eles investem o seu código de escrita de esforço duro para consumir a sua API, então você melhorará muito, não vá e quebre-a mais na linha.


Honestamente, os debates sobre o que é & # x201C; RESTful & # x201D; versus o que não é como se o próprio termo ditar seu sucesso é apenas louco. Transforme essa discussão em & # x201C; Aqui estão os motivos práticos pelos quais isso faz sentido e isso é o que pode acontecer se você não fizer isso e # x201D ;, e eu e todos os ouvidos. O problema é que até mesmo as vozes da razão nas discussões barulhentas deixam dúvidas sobre o que realmente é a melhor abordagem e, portanto, eu alcancei um compromisso & # x2026;


Aqui estão 3 maneiras erradas de consumir a API HIBP que você pode escolher agora.


Ok, agora que nós estabelecemos claramente o que você faz é errado, eu gostaria de lhe dar a escolha de escolher entre qualquer uma das 3 maneiras erradas. Aguarde & # x2018; o que?! É assim: no entanto, implemento a API, será muito difícil de consumir, muito acadêmico, muito provável que falhe no proxy ou algo como algo. Ao invés de escolher 1 maneira errada, eu decidi você dar todas as 3 maneiras erradas e você pode escolher aquele que é o menos errado para você.


Wrong way 2 - cabeçalho de solicitação personalizado:


Inevitavelmente, alguém me dirá que fornecer 3 maneiras erradas é a coisa errada a fazer. Won & # x2019; t significa mais código kludge para manter? Não, simplesmente significa que a implementação da API da Web subjacente é decorada com dois atributos:


O primeiro é simplesmente uma restrição de roteamento que implementa RouteFactoryAttribute. Eu passo na rota e passa na versão que pode mapear para essa rota, então a implementação procura a presença de uma & # x201C; api-version & # x201D; cabeçalho ou um cabeçalho de aceitação correspondente a este padrão:


Se a versão especificada em qualquer uma dessas combina com a especificada na restrição de roteamento, então esse é 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 vem com cortesia da Web API 2 e o recurso de roteamento de atributos. Claro que sempre poderíamos fazer o roteamento na API da Web, mas geralmente foi definido globalmente. O roteamento de atributos como esse traz a definição da rota para o contexto onde ela é aplicada e torna mais fácil ver qual ação do controlador vai ser chamada por qual rota. Isso também significa que as implementações para todas as 3 maneiras erradas de chamar a API se juntam em um local limpo.


Então, em suma, não, isso não cria muito kludge e é muito fácil de manter. Cada uma das 3 abordagens retornará exatamente o mesmo resultado e, o mais importante, eles permanecerão estáveis ​​e ganharão mudar em qualquer maneira de quebrar e, no final do dia, isso é o máximo coisa importante, independentemente da opção que você escolher. A implementação inteira agora também está claramente documentada na página API do site.


Mas e se você não especificar uma versão?


Você conhece o pouco onde eu disse que você pode quebrar o que já existe? Sim, então isso significa que se você fizer o que faz agora & # x2018; não especifique uma versão & # x2018; então você obtém o que você recebe agora. Em outras palavras, nenhum pedido para uma versão específica significa que você obteve a versão 1.


Estou bem com isso, independentemente de ter alcançado 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 & # x201C; estável & # x201D; objetivo; O que você obtém da API hoje pode ser completamente diferente do que você obtém amanhã se eu a revisar. Isso sugaria e isso quebraria coisas.


Você tem 3 opções, mas minha preferência pessoal é & # x2026;


Tenho o luxo de controlar a API e o principal consumidor de ser o próprio site da HIBP. Dado que eu forneci 3 opções para consumir a API, qual eu uso eu?


Eu fui com o favorito filosófico que é especificá-lo através do cabeçalho de aceitação. Eu não acho que isso é correto e os outros estão errados, e acho que isso faz mais sentido por duas razões principais:


Eu concordo que o URL não deve ser alterado: se concordarmos que o URL representa o recurso, a menos que tenhamos tentado representar diferentes versões do próprio recurso, então não, eu não acho que o URL deve mudar. As brechas para foo são sempre as brechas para foo e eu não acho que apenas porque eu mudo os dados retornados para que a localização do foo mude. Eu concordo que aceitar cabeçalho descreva como você gosta dos dados: Esta é uma semântica da especificação HTTP e assim como a semântica dos verbos de solicitação faz muito sentido (ou seja, estamos recebendo ou colocando ou excluindo ou postando) Da mesma forma, a maneira como o cliente gostaria que o conteúdo fosse representado.


By no means does this mean that I think the other two are wrong and frankly, there’s no better way to share the API with someone than to say “Here, click this”, but when I can easily construct the request and manage the headers, I’ve gone with this route.


Actually, come to think of it, I also use the version in the domain route. Por quê? Just through the process of writing this API I was constantly communicating with people about the ways of querying it (more on that later) and the attributes it returns. Being able to go flick an email and say “Hey, here’s what I’m thinking” and they simply click it and get results is invaluable. This is the point that proponents of the URL versioning approach quite rightly make: you simply cannot do this when you’re dependent on headers.


Oh, and in case you’re checking up on me, at the time of writing I haven’t yet rolled the site over to v2 of the API. Now that the breach data is pulled back in the API when a search occurs it means I have the luxury of not loading all breaches into the source on initial load (that was never going to be sustainable as the data set expands). This’ll save a bunch of outbound traffic and speed things up for people in terms of getting the site loaded, but it also means just a little more work on my end. Fique ligado.


No encerramento.


Clearly I’ve been a little tongue-in-cheek here with regards to everything being wrong but honestly, the more you read on this and the more questions you ask, the more wrong every route seems in one way or another. In fact I know damn well that there are aspects of my implementation that will be referred to as “wrong” (I can think of at least a couple) and naturally I’m bracing for the potential onslaught of feedback to that effect. The thing is though, each of these options works and frankly, for all practical purposes, they work just as well as each other.


If I may leave others considering how to version their APIs with a final thought: Nobody will use your API until you’ve built it. Stop procrastinating. None of these are “bad” in any tangible sense, they’re just different. They are all easily consumable, they all return the same result and none of them are likely to have any real impact on the success of your project.


Referências.


Stack Overflow: Best practices for API versioning? (great question, great answers, closed as “not constructive”, I assume because “Bill the Lizard” got out on the wrong side of bed that morning) Lexical Scope blog: How are REST APIs versioned? (good comparison of versioning practices across services. albeit now a couple of years old) CodePlex: Routing constraint sample (linked in from Microsoft’s Web API page as an example of versioning APIs by adding a custom header) CodeBetter: Versioning RESTful Services (very pragmatic and a good description of the various ways an API might change) Vinay Sahni’s blog: Best Practices for Designing a Pragmatic RESTful API (he’s arguing for URL versioning for the sake of “browser explorability”) Pivotal Lans: API versioning (good view of the conflicting opinions out there) Web Stack of Love: ASP Web API Versioning with Media Types (good end-to-end walkthrough of creating an app to support 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.


Próximos eventos.


I usually run private workshops around these, here's the upcoming public events I'll be at:


Don't have Pluralsight already? How about a 10 day free trial? That'll get you access to thousands of courses amongst which are dozens of my own including:


“The Cloud Never Goes Down”, Azure SLAs and other availability trivia.


Here’s how Bell was hacked – SQL injection blow-by-blow.


Subscribe Now!


Copyright 2017, Troy Hunt.


This work is licensed under a Creative Commons Attribution 4.0 International License. In other words, share generously but provide attribution.


Aviso Legal.


Opinions expressed here are my own and may not reflect those of people I work with, my mates, my wife, the kids etc. Unless I'm quoting someone, they're just my own views.


Published with Ghost.


This site runs entirely on Ghost and is made possible thanks to their kind support. Read more about why I chose to use Ghost.


Four REST API Versioning Strategies.


This article describes four common REST API versioning strategies and explains how we version the REST API at xMatters.


At xMatters, we follow the SemVer specification – we update the API major version whenever we introduce breaking changes. Internally, we update minor and patch versions whenever we add functionality and backward-compatible updates. When we release a new major version of the xMatters REST API, clients can choose to either continue using an existing major version or migrate to the new one.


REST is by far the most prominent architectural style used today to expose services to third parties over the internet. It uses the HTTP standard instead of more complex protocols like SOAP or RPC. The reason REST has been so successful is that it mimics how the web works:


Stateless: Doesn’t retain client context between requests Cacheable: Relies on HTTP caching rules Client/Server oriented: Separates concerns between clients and servers Layered: Leverages a layered system and a unified interface.


Four common REST API versioning strategies.


There are four common ways to version a REST API.


1. Versioning through URI Path.


One way to version a REST API is to include the version number in the URL path.


This strategy is used by xMatters as well as other companies such as Facebook, Twitter, Airbnb, and others.


This solution often uses URI routing to point to a specific version of the API. Because cache keys (in this situation URIs) are changed by version, clients can easily cache resources. When a new version of the REST API is released, it is perceived as a new entry in the cache.


The internal version of the API looks as follows:


Major version: The version used in the URI and denotes breaking changes to the API. Internally, a new major version implies creating a new API and the version number is used to route to the correct host.


Minor and Patch versions: These are transparent to the client and used internally for backward-compatible updates. They are usually communicated in change logs to inform clients about a new functionality or a bug fix.


This solution has a pretty big footprint in the code base as introducing breaking changes implies branching the entire API.


2. Versioning through query parameters.


Another option for versioning a REST API is to include the version number as a query parameter.


This is a straightforward way of versioning an API from an implementation point of view. It is also easy to default to the latest version if a query parameter is not specified.


The main drawback comparing to the URI versioning is the difficulty of routing. Query parameters are in fact more difficult to use for routing requests to the proper API version.


3. Versioning through custom headers.


REST APIs can also be versioned by providing custom headers with the version number included as an attribute.


The main difference between this approach and the two previous ones is that it doesn’t clutter the URI with versioning information.


4. Versioning through content negotiation.


curl - H “Accept: application/vnd. xm. device+json; version=1 ” example/api/products.


The last strategy we are addressing is versioning through content negotiation.


This approach allows us to version a single resource representation instead of versioning the entire API which gives us a more granular control over versioning. It also creates a smaller footprint in the code base as we don’t have to fork the entire application when creating a new version. Another advantage of this approach is that it doesn’t require implementing URI routing rules introduced by versioning through the URI path.


One of the drawbacks of this approach is that it is less accessible than URI-versioned APIs: Requiring HTTP headers with media types makes it more difficult to test and explore the API using a browser.


Content negotiation is a more granular approach because it versions resource representations instead of versioning the entire API, but it also comes with a high implementation cost for both clients and developers. More often than not, content negotiation needs to be implemented from scratch as there are few libraries that offer that out of the box. The other approaches are easier to implement and use but limit the developer’s ability to refactor due to the high cost of introducing breaking changes to the API contract.


Any thoughts or recommendations? Deixe um comentário abaixo!


Free White Paper: Learn About Standard+Case.


Learn more about taking a holistic approach to IT from Rob England at his blog, The IT Skeptic, and from his books, including Plus! The Standard+Case Approach. For more information, read Rob’s new white paper on turning undefined Case Management situations into new Standard Response Models, written for xMatters: Standard+Case: How IT Response Models Drive Modern Operations.


Do we need to make packging (folder) as per the major version ?


Another question is, How the version the schema if Api change require change in database tables. any link ?


One thing that is not very often documented is how to manage the code and all the versions that are supported by the API.


I’m interested to find a good pattern to manage our code and avoid version nightmare.


My implementation of 3rd approach for spring-webmvc:


Você também pode estar interessado em.


How We Hacked the Airbnb experience with AT&T, HP, and Intel.


New ServiceNow Integration Reduces Time to Resolve.


Moogsoft and xMatters Integration Takes Incident Management to a New Level.


Zombie Jobs Can’t Be Stopped By Email Broadcasts.


Need support?


Our dedicated community site is the best place to get help on all xMatters products. Our team of expert support staff and users inside our community can help you get the right answer.


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.


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.


Forget code coverage – test design should be driven by behaviours.


Test coverage statistics are much loved by management teams and code quality tools. They tend to associate a high level of coverage with robust, well-managed code bases. Wrongly, as it turns out.


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.


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.


How can Domain Driven Design help with large scale agile development?


Agile teams spend time modelling software whether they are prepared to admit it or not. Adopting a technique like Domain Driven Design can help to make this more efficient, particularly at scale.


Running a Core console application as a Windows Service.


Although Core does not directly support creating Windows Services there are several different ways of creating applications that can be registered and run as services.


When does refactoring become rewriting?


Refactoring describes a very specific and controlled technique for improving code. The problem is that it is often used to describe wholesale changes to code bases that should be treated as a rewrite.


Writing unit tests for Azure Functions using C#


You can now write compiled Azure functions in C# with full unit test coverage, though there are a few obstacles along the way.

No comments:

Post a Comment