Implementar operações de controlo de versões

Os conectores personalizados para Azure Logic Apps, Microsoft Power Automate ou Microsoft Power Apps têm de fornecer um ficheiro de especificações do OpenAPI. Esta especificação OpenAPI define pontos de entrada individuais, que são chamados operações. Cada operação tem um operationId exclusivo e um urlPath e uma combinação de HttpVerb exclusivos.

{
    "/items": {
        "get": {
            "summary": "Get rows",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems"
        },
        "post": {
            "summary": "Insert row",
            "description": "This operation inserts an item.",
            "operationId": "PostItem"
        }
    }
}

Estas operações podem crescer e sofrer alterações ao longo do tempo, à medida que são adicionadas funcionalidades ou que estas se expandem. Algumas alterações são meros acrescentos e não quebram necessariamente o contrato que existe entre os clientes e os servidores. Esta categoria inclui adicionar parâmetros novos, devolver mais dados ou permitir entradas mais flexíveis.

No entanto, há muitas alterações que podem efetivamente quebrar o contrato descrito na especificação OpenAPI. Esta categoria de "alterações interruptivas" inclui remover parâmetros, deixar de suportar determinadas entradas ou mudar o significado e o comportamento de uma entrada ou saída ou da própria operação.

Para desenvolver uma API em segurança, é importante seguir um padrão que os clientes consigam navegar. Cabe à API manter a retrocompatibilidade, comunicar a intenção e delinear atributos de versão. É da responsabilidade do cliente mostrar ou ocultar as operações preteridas, expiradas ou que possam ter versões novas disponíveis. Dessa forma, as operações podem crescer e desenvolver-se ao longo do tempo sem provocar fragilidades indevidas nas aplicações que dependem das mesmas.

Anotação de API

OpenAPI não tem suporte intrínseco para controlo de versão operacional. Para atingirmos o nosso objetivo, muito do trabalho é feito no objeto x-ms-api-annotation, que é aplicado quer no âmbito global, quer no âmbito da operação. O objeto global contém propriedades que se aplicam à API como um todo:

{
    "x-ms-api-annotation": {
        "status": "Preview"
    }
}
Propriedade Valores Predefinição Descrição
estado "Preview" "Production" "Preview" O estado da API como um todo — começando na Pré-visualização e escalando para a Produção conforme ditado pela utilização e pela estabilidade

No âmbito operacional, este objeto contém propriedades mais detalhadas. Também existem propriedades adicionais fora do objeto que se aplicam e participam no processo de desenvolvimento de versões:

{
    "deprecated": true,
    "x-ms-api-annotation": {
        "status": "Production",
        "family": "MyOperation",
        "revision": 2
    }
}
Propriedade Valores Predefinição Descrição
preterido null false true false Indica se a operação foi preterida
x-ms-visibility null "" "Important" "Advanced" "Internal" "" A visibilidade e proeminência pretendidas desta operação, em que null ou "" implica o estado Normal
estado "Preview" "Production" "Production" O estado da operação — pode ser diferente do estado da própria API; contudo, se não for especificado, herda do estado de nível superior da API
família {nome comum da operação} operationName O nome que se aplica a todas as revisões desta operação
revisão numérico (1,2,3...) 1 A revisão da família operacional especificada
expira em Data do ISO8601 (nenhum) Sugestão opcional para o cliente para indicar o fim projetado do suporte

Preterido pode ser definido como true quando deixar de ser desejável que os clientes utilizem esta operação. Esta propriedade existe na especificação Campos Fixos de OpenAPI.

Visibilidade é um indicador da proeminência relativa pretendida da operação. A visibilidade "Important" indica que a operação deve estar na parte superior da lista e ser apresentada de forma destacada. A visibilidade normal (indicada por meio de null ou da cadeia vazia "") é a predefinição e significa que a operação vai aparecer na lista, provavelmente a seguir às operações Importantes. A visibilidade "Advanced" indica que a operação pode aparecer na parte inferior da lista ou mesmo ser ocultada de início por trás de um controlo de expansão. As operações avançadas podem ser de utilização mais difícil, menos populares ou ter uma aplicação mais restrita. A visibilidade "Internal" indica que a operação não deve ser exposta aos utilizadores e que só deve ser utilizada internamente. As operações internas são programaticamente úteis e importantes, mas não se destinam a ser utilizadas pelos utilizadores finais. Também podem ser marcadas como tal para que sejam ocultadas de qualquer tipo de IU durante o processo de preterição sem as remover efetivamente da API, o que originaria uma alteração interruptiva.

Status indica a estabilidade da API ou da operação. "Preview" indica que a operação ou API é nova e potencialmente não comprovada. A pré-visualização é um indicador de que os sistemas de produção devem ser reservados no que diz respeito a presumir dependências. Quando a operação ou a API estiver mais estabelecida e tiver provado que cumpre os padrões de fiabilidade, taxa de sucesso e escalabilidade, pode ser intencionalmente atualizada para o estado "Production".

Os seguintes requisitos de métricas aplicam-se geralmente às operações que procuram obter o estado "Production":

  • Taxa de sucesso de 80% por um período de três semanas
    • definida como percentagem dos códigos de resposta HTTP no intervalo 2xx
  • 99,9% de fiabilidade sustentada por um período de três semanas
    • definida como percentagem dos códigos de resposta HTTP no intervalo não 5xx (502, 504 e 520 estão excluídos deste cálculo)

Family indica a relação entre as operações que são conceptualmente as mesmas, mas que se tratam de diferentes revisões com alterações potencialmente interruptivas entre si. Várias operações partilharão o mesmo nome de família caso devam ser consideradas revisões umas das outras e são ordenadas pelos números de revisão exclusivos.

Revision indica a ordem de desenvolvimento da operação dentro da família de operações. Cada operação numa família terá uma revisão que é um índice integral que pressupõe sequência. As revisões vazias serão consideradas a revisão 1. Quando estiverem disponíveis revisões mais recentes de uma operação, os clientes devem apresentá-las de forma mais proeminente e recomendá-las mais intencionalmente, mas, ainda assim, permitir que sejam selecionadas revisões potencialmente mais antigas que ainda não tenham sido preteridas.

Expira é opcional e indica um potencial prazo de fim de vida, no qual o suporte da operação deixa de ser garantido. Só deve ser definido para operações preteridas e, atualmente, não está refletido em nenhuma interface.

Tempo de Vida Operacional

As operações têm um tempo de vida previsível que pode ser mostrado por exemplo.

Ponto de Início

De início, as operações podem não necessariamente indicar nada sobre as revisões. Estas operações têm aplicadas a si predefinições, pelo que são consideradas a revisão 1 num nome de família equivalente ao operationId.

{
    "/{list}/items": {
        "get": {
            "summary": "Get rows",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems"
        }
    }
}

Isto é equivalente à definição mais explícita:

{
    "/{list}/items": {
        "get": {
            "summary": "Get rows",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems",
            "deprecated": false,
            "x-ms-api-annotation": {
                "status": "Production",
                "family": "GetItems",
                "revision": 1
            }
        }
    }
}

Início da Operação

A maioria das evoluções das APIs constituem o acrescento de uma operação. Por exemplo, novos métodos e novas revisões de métodos já existentes. Para iniciar uma revisão nova em segurança, pode ajustar a especificação OpenAPI da seguinte forma:

{
    "/{list}/items": {
        "get": {
            "summary": "Get rows (V1 - downplayed)",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems",
            "deprecated": false,
            "x-ms-visibility": "advanced",
            "x-ms-api-annotation": {
                "status": "Production",
                "family": "GetItems",
                "revision": 1
            }
        }
    }
    "/v2/{list}/items": {
        "get": {
            "summary": "Get rows (V2 - new hotness)",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems_V2",
            "deprecated": false,
            "x-ms-api-annotation": {
                "status": "Preview",
                "family": "GetItems",
                "revision": 2
            }
        }
    }
}

Importante

Repare que GetItems V2 tem um operationId exclusivo e é inicialmente apresentado com o estado de pré-visualização. Repare também que, agora, a visibilidade de GetItems V1 é avançada, pelo que não é apresentado com tanta proeminência.

Preterição da Operação

Por vezes, os pontos de entrada V1 já existentes permanecem indefinidamente caso continuem a gerar valor e não houver nenhum motivo convincente para os terminar. No entanto, muitos pontos de entrada V2 substituem intencionalmente o ponto de entrada V1. Para o fazer em segurança, todo o tráfego deve atingir zero nominal na operação original. Quando a telemetria confirmar esta circunstância, pode ser feita a seguinte alteração:

{
    "/{list}/items": {
        "get": {
            "summary": "Get rows (deprecated)",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems",
            "deprecated": true,
            "x-ms-api-annotation": {
                "status": "Production",
                "family": "GetItems",
                "revision": 1
            }
        }
    }
    "/v2/{list}/items": {
        "get": {
            "summary": "Get rows",
            "description": "This operation gets a list of items.",
            "operationId": "GetItems_V2",
            "deprecated": false,
            "x-ms-api-annotation": {
                "status": "Production",
                "family": "GetItems",
                "revision": 2
            }
        }
    }
}

Importante

Repare que GetItems V1 está agora marcado como preterido. Esta é a transição final para preterir operações. GetItems V2 substituiu agora completamente GetItems V1.

Porquê dar-se ao trabalho?

Há muitos motivos para aderir ao controlo de versões operacionais. Em primeiro lugar, é uma forma de garantir que os clientes como o Azure Logic Apps e o Power Automate continuam a funcionar corretamente quando os utilizadores integram operações de conectores nos respetivos fluxos de dados. O controlo de versões deve ser aplicado às operações com o método anterior sempre que:

  • É adicionada uma revisão nova de uma operação
  • Uma operação já existente adiciona ou remove parâmetros
  • Uma operação já existente altera a entrada ou a saída de forma significativa

Estritamente falando

Poderá haver casos em que as coisas funcionam bem sem o controlo de versões—, mas deverá ter cuidado se optar por isso e deverá fazer muitos testes para ter a certeza de que não ignorou casos extremos em que os utilizadores podem deixar de conseguir trabalhar. Segue-se a lista resumida de precauções a ter se optar por não o utilizar:

  • É adicionada uma operação nova.

    Isto não interromperá especificamente os clientes existentes.

  • É adicionado um novo parâmetro opcional a uma operação existente.

    Isto não interromperá as chamadas existentes, mas deve ser considerado cuidadosamente.

  • O comportamento de uma operação existente muda subtilmente.

    Esta situação pode danificar os chamadores existentes dependendo da natureza da alteração e naquilo de que os utilizadores dependem. e é a mas precária de todas as situações, pois uma diferença significativa na aceitação de entradas, na geração de saídas, no timing ou no processamento poderá afetar o comportamento da operação de formas que tornam difícil determinar o risco da alteração.

É sempre recomendável errar, por questões de cuidado, e iterar uma revisão sempre que fizer alterações não triviais às APIs.

Enviar comentários

Apreciamos os comentários sobre problemas com a nossa plataforma de conectores ou novas ideias de funcionalidades. Para enviar comentários, aceda a Submeter problemas ou obter ajuda com conectores e selecione o tipo de comentários.