Conectar o Azure Functions ao Azure Cosmos DB usando o Visual Studio Code

O Azure Functions lhe permite conectar os serviços do Azure e outros recursos às funções sem precisar escrever seu próprio código de integração. Essas associações, que representam a entrada e a saída, são declaradas na definição de função. Dados de associações são fornecidos à função como parâmetros. Um gatilho é um tipo especial de associação de entrada. Embora uma função tenha apenas um gatilho, ela pode ter várias associações de entrada e de saída. Para saber mais, confira Conceitos de gatilhos e de associações do Azure Functions.

Este artigo mostrará de que modo usar o Visual Studio Code para conectar o Azure Cosmos DB à função criada no artigo anterior do guia de início rápido. A associação de saída adicionada a essa função gravará dados da solicitação HTTP em um documento JSON armazenado em um contêiner do Azure Cosmos DB.

Antes de começar, você precisa concluir o Guia de início rápido: Criar uma função C# no Azure usando o Visual Studio Code. Se você já limpou os recursos ao final daquele artigo, percorra as etapas novamente para recriar o aplicativo de funções e recursos relacionados no Azure.

Antes de começar, você precisa concluir o Guia de início rápido: Criar uma função JavaScript no Azure usando o Visual Studio Code. Se você já limpou os recursos ao final daquele artigo, percorra as etapas novamente para recriar o aplicativo de funções e recursos relacionados no Azure.

Observação

No momento, este artigo só dá suporte ao Node.js v3 para Functions.

Antes de começar, você precisa concluir o Guia de início rápido: Criar uma função do Python no Azure usando o Visual Studio Code. Se você já limpou os recursos ao final daquele artigo, percorra as etapas novamente para recriar o aplicativo de funções e recursos relacionados no Azure.

Configurar seu ambiente

Antes de começar, lembre-se de instalar a extensão de Bancos de Dados do Azure no Visual Studio Code.

Criar uma conta do Azure Cosmos DB

Agora, você cria uma conta do Azure Cosmos DB como um tipo de conta sem servidor. Esse modo baseado em consumo torna o Azure Cosmos DB uma opção forte para cargas de trabalho sem servidor.

  1. No Visual Studio Code, selecione Exibir>Paleta de Comandos… e, na paleta de comandos, pesquise Azure Databases: Create Server...

  2. Forneça as seguintes informações nos prompts:

    Prompt Seleção
    Selecionar um servidor de banco de dados do Azure Escolha Core (NoSQL) para criar um banco de dados de documento que você pode consultar usando uma sintaxe SQL ou um Copilot de Consulta (Versão Prévia) convertendo prompts de linguagem natural em consultas. Saiba mais sobre o Azure Cosmos DB.
    Nome da Conta Insira um nome exclusivo para identificar a conta do Azure Cosmos DB. O nome da conta pode usar apenas letras minúsculas, números e hifens (-) e deve ter de 3 a 31 caracteres.
    Selecione um modelo de capacidade Selecione Sem servidor para criar uma conta no modo sem servidor.
    Selecione um grupo de recursos para novos recursos Escolha o grupo de recursos em que o aplicativo de funções foi criado no artigo anterior.
    Selecione uma localização para novos recursos Selecione uma localização geográfica para hospedar a sua conta do Azure Cosmos DB. Use a localização mais próxima de você ou de seus usuários para obter um acesso mais rápido aos dados.

    Depois que a nova conta for provisionada, uma mensagem será exibida na área de notificação.

Criar um banco de dados e um contêiner do Azure Cosmos DB

  1. Selecione o ícone do Azure na Barra de atividades, expanda Recursos>Azure Cosmos DB, clique com o botão direito do mouse (CTRL + seleção no macOS) na sua conta e escolha Criar banco de dados….

  2. Forneça as seguintes informações nos prompts:

    Prompt Seleção
    Nome do banco de dados Digite my-database.
    Insira uma ID para sua coleção Digite my-container.
    Insira a chave de partição para a coleção Digite /id como a chave de partição.
  3. Selecione OK para criar o contêiner e o banco de dados.

Atualizar as configurações do aplicativo de funções

No artigo anterior do guia de início rápido, um aplicativo de funções foi criado no Azure. Neste artigo, você atualizará seu aplicativo para gravar documentos JSON no contêiner do Azure Cosmos DB criado. Para se conectar à conta do Azure Cosmos DB, será necessário adicionar a cadeia de conexão dela às configurações do aplicativo. Depois baixe a nova configuração no arquivo local.settings.json para que seja possível se conectar à conta do Azure Cosmos DB quando ela estiver em execução localmente.

  1. No Visual Studio Code, clique com o botão direito do mouse (CTRL + seleção no macOS) na sua nova conta do Azure Cosmos DB e escolha Copiar Cadeia de Conexão.

    Como copiar a cadeia de conexão do Azure Cosmos DB

  2. Pressione a tecla F1 para abrir a paleta de comandos, depois pesquise e execute o comando Azure Functions: Add New Setting....

  3. Escolha o aplicativo de função que você criou no artigo anterior. Forneça as seguintes informações nos prompts:

    Prompt Seleção
    Insira o nome da configuração do novo aplicativo Digite CosmosDbConnectionSetting.
    Insira o valor para "CosmosDbConnectionSetting" Cole a cadeia de conexão da sua conta do Azure Cosmos DB que você copiou. Você também pode configurar a identidade do Microsoft Entra como alternativa.

    Isso cria uma conexão nomeada da configuração de aplicativo CosmosDbConnectionSetting no seu aplicativo de funções no Azure. Agora, você pode baixar essa configuração no arquivo local.settings.json.

  4. Pressione a tecla F1 novamente para abrir a paleta de comandos, depois pesquise e execute o comando Azure Functions: Download Remote Settings....

  5. Escolha o aplicativo de função que você criou no artigo anterior. Selecione Sim para todos para substituir as configurações locais existentes.

Isso baixa toda a configuração do Azure para seu projeto local, incluindo a nova configuração da cadeia de conexão. A maioria das configurações baixadas não é usada durante a execução local.

Registrar as extensões de associação

Como você está usando uma associação de saída do Azure Cosmos DB, será necessário obter a extensão das associações correspondentes instalada antes de executar o projeto.

Com exceção dos gatilhos de timer e HTTP, as associações são implementadas como pacotes de extensão. Execute o comando dotnet add package a seguir na janela Terminal para adicionar o pacote de extensão do Azure Cosmos DB ao seu projeto.

dotnet add package Microsoft.Azure.Functions.Worker.Extensions.CosmosDB

Seu projeto foi configurado para usar pacotes de extensão, que instalam automaticamente um conjunto predefinido de pacotes de extensão.

O uso de pacotes de extensão é habilitado no arquivo host.json na raiz do projeto, cuja aparência é semelhante à seguinte:

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.0.0)"
  },
  "concurrency": {
    "dynamicConcurrencyEnabled": true,
    "snapshotPersistenceEnabled": true
  },
  "extensions": {
    "cosmosDB": {
      "connectionMode": "Gateway"
    }
  }
}

Seu projeto foi configurado para usar pacotes de extensão, que instalam automaticamente um conjunto predefinido de pacotes de extensão.

O uso de pacotes de extensão é habilitado no arquivo host.json na raiz do projeto, cuja aparência é semelhante à seguinte:

{
  "version": "2.0",
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[3.*, 4.0.0)"
  } 
}

Agora é possível adicionar a associação de saída do Azure Cosmos DB ao seu projeto.

Adicionar uma associação de saída

Em um projeto de biblioteca de classes C#, as associações são definidas como atributos de associação no método de função.

Abra o arquivo de projeto HttpExample.cs e adicione as seguintes classes:

public class MultiResponse
{
    [CosmosDBOutput("my-database", "my-container",
        Connection = "CosmosDbConnectionSetting", CreateIfNotExists = true)]
    public MyDocument Document { get; set; }
    public HttpResponseData HttpResponse { get; set; }
}
public class MyDocument {
    public string id { get; set; }
    public string message { get; set; }
}

A classe MyDocument define um objeto que é gravado no banco de dados. A cadeia de conexão para a conta de armazenamento é definida pela propriedade Connection. Nesse caso, você poderia omitir Connection porque já está usando a conta de armazenamento padrão.

A classe MultiResponse permite que você faz gravações na coleção especificada do Azure Cosmos DB e retorne uma mensagem de êxito HTTP. Como você precisa retornar um objeto MultiResponse, também precisa atualizar a assinatura do método.

Os atributos específicos indicam o nome do contêiner e do nome do banco de dados pai. A cadeia de conexão de sua conta do Azure Cosmos DB será definida pelo CosmosDbConnectionSetting.

Os atributos de associação são definidos diretamente no código da função. A configuração de saída do Azure Cosmos DB descreve os campos necessários para executar uma associação de saída do Azure Cosmos DB.

Para esse cenário MultiResponse, você precisa adicionar uma associação de saída extraOutputs à função.

app.http('HttpExample', {
  methods: ['GET', 'POST'],
  extraOutputs: [sendToCosmosDb],
  handler: async (request, context) => {

Adicione as seguintes propriedades à configuração de associação:

const sendToCosmosDb = output.cosmosDB({
  databaseName: 'my-database',
  containerName: 'my-container',
  createIfNotExists: false,
  connection: 'CosmosDBConnectionString',
});

Os atributos de associação são definidos diretamente no arquivo function_app.py. Use o decorador cosmos_db_output para adicionar uma associação de saída do Azure Cosmos DB:

@app.cosmos_db_output(arg_name="outputDocument", database_name="my-database", 
    container_name="my-container", connection="CosmosDbConnectionSetting")

Nesse código, arg_name identifica o parâmetro de associação referenciado no código, database_name e container_name são os nomes do banco de dados e da coleção nos quais a associação faz a gravação e connection é o nome de uma configuração de aplicativo que contém a cadeia de conexão para a conta do Azure Cosmos DB, que está na configuração CosmosDbConnectionSetting no arquivo local.settings.json.

Adicionar o código que usa a associação de saída

Substitua o método Run existente pelo seguinte código:

[Function("HttpExample")]
public static MultiResponse Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
    FunctionContext executionContext)
{
    var logger = executionContext.GetLogger("HttpExample");
    logger.LogInformation("C# HTTP trigger function processed a request.");

    var message = "Welcome to Azure Functions!";

    var response = req.CreateResponse(HttpStatusCode.OK);
    response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
    response.WriteString(message);

    // Return a response to both HTTP trigger and Azure Cosmos DB output binding.
    return new MultiResponse()
    {
         Document = new MyDocument
        {
            id = System.Guid.NewGuid().ToString(),
            message = message
        },
        HttpResponse = response
    };
}

Adicione o código que usa o objeto de associação de saída extraInputs em context para enviar um documento JSON para a função de associação de saída nomeada, sendToCosmosDb. Adicione esse código antes da instrução return.

context.extraOutputs.set(sendToCosmosDb, {
  // create a random ID
  id:
    new Date().toISOString() + Math.random().toString().substring(2, 10),
  name: name,
});

Neste ponto, sua função deve ser a seguinte:

const { app, output } = require('@azure/functions');

const sendToCosmosDb = output.cosmosDB({
  databaseName: 'my-database',
  containerName: 'my-container',
  createIfNotExists: false,
  connection: 'CosmosDBConnectionString',
});

app.http('HttpExampleToCosmosDB', {
  methods: ['GET', 'POST'],
  extraOutputs: [sendToCosmosDb],
  handler: async (request, context) => {
    try {
      context.log(`Http function processed request for url "${request.url}"`);

      const name = request.query.get('name') || (await request.text());

      if (!name) {
        return { status: 404, body: 'Missing required data' };
      }

      // Output to Database
      context.extraOutputs.set(sendToCosmosDb, {
        // create a random ID
        id:
          new Date().toISOString() + Math.random().toString().substring(2, 10),
        name: name,
      });

      const responseMessage = name
        ? 'Hello, ' +
          name +
          '. This HTTP triggered function executed successfully.'
        : 'This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.';

      // Return to HTTP client
      return { body: responseMessage };
    } catch (error) {
      context.log(`Error: ${error}`);
      return { status: 500, body: 'Internal Server Error' };
    }
  },
});

Este código agora retorna um objeto MultiResponse que contém um documento e uma resposta HTTP.

Atualize HttpExample\function_app.py para correspondê-lo ao código a seguir. Atualize o parâmetro outputDocument à definição de função e outputDocument.set() abaixo da instrução if name::

import azure.functions as func
import logging

app = func.FunctionApp()

@app.function_name(name="HttpTrigger1")
@app.route(route="hello", auth_level=func.AuthLevel.ANONYMOUS)
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
@app.cosmos_db_output(arg_name="outputDocument", database_name="my-database", container_name="my-container", connection="CosmosDbConnectionSetting")
def test_function(req: func.HttpRequest, msg: func.Out[func.QueueMessage],
    outputDocument: func.Out[func.Document]) -> func.HttpResponse:
     logging.info('Python HTTP trigger function processed a request.')
     logging.info('Python Cosmos DB trigger function processed a request.')
     name = req.params.get('name')
     if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

     if name:
        outputDocument.set(func.Document.from_dict({"id": name}))
        msg.set(name)
        return func.HttpResponse(f"Hello {name}!")
     else:
        return func.HttpResponse(
                    "Please pass a name on the query string or in the request body",
                    status_code=400
                )

O documento {"id": "name"} é criado na coleção de banco de dados especificada na associação.

Executar a função localmente

O Visual Studio Code integra-se ao Azure Functions Core Tools para permitir que você execute esse projeto em seu computador de desenvolvimento local antes da publicação no Azure. Se você ainda não tiver o Core Tools instalado localmente, será solicitado que você o instale na primeira vez que executar o projeto.

  1. Para chamar sua função, pressione F5 para iniciar o projeto de aplicativo de funções. O painel Terminal exibirá a saída do Core Tools. Seu aplicativo é iniciado no painel Terminal. Você pode ver o ponto de extremidade de URL de sua função disparada por HTTP localmente.

    Captura de tela da saída do Visual Studio Code da função local.

    Se o Core Tools ainda não estiver instalado, selecione Instalar para instalar o Core Tools quando solicitado a fazê-lo.
    Se você tiver problemas com a execução no Windows, verifique se o terminal padrão do Visual Studio Code não está definido como bash WSL.

  2. Com o Core Tools em execução, acesse a área Azure: Funções. Em Funções, expanda Projeto Local>Funções. Clique com o botão direito do mouse (Windows) ou clique em CTRL - (macOS) na função HttpExample e escolha Função Executar Agora... .

    Captura de executar função agora no Visual Studio Code.

  3. Em Insira o corpo da solicitação, pressione ENTER para enviar uma mensagem à função.

  4. Quando a função é executada localmente e retorna uma resposta, uma notificação é gerada no Visual Studio Code. As informações sobre a execução da função são mostradas no painel Terminal.

  5. Pressione Ctrl + C para parar o Core Tools e desconectar o depurador.

Executar a função localmente

  1. Como no artigo anterior, clique em F5 para iniciar o projeto do aplicativo de funções e o Core Tools.

  2. Com o Core Tools em execução, acesse a área Azure: Funções. Em Funções, expanda Projeto Local>Funções. Clique com o botão direito do mouse (CTRL-clique no Mac) na função HttpExample e escolha Executar Função Agora... .

    Executar a função agora por meio do Visual Studio Code

  3. Em Insira o corpo da solicitação, você verá o valor do corpo da mensagem de solicitação igual a { "name": "Azure" }. Clique em ENTER para enviar essa mensagem de solicitação à função.

  4. Depois que uma resposta for retornada, clique em CTRL + C para interromper o Core Tools.

Verificar se o documento JSON foi criado

  1. No portal do Azure, navegue de volta para sua conta do Azure Cosmos DB e selecione Data Explorer.

  2. Expanda o banco de dados e o contêiner, depois selecione Itens para listar os documentos criados em seu contêiner.

  3. Verifique se um documento JSON foi criado pela associação de saída.

    Como verificar se um documento foi criado no contêiner do Azure Cosmos DB

Reimplementar e verificar o aplicativo atualizado

  1. No Visual Studio Code, pressione F1 para abrir a paleta de comandos. Na paleta de comandos, pesquise e selecione Azure Functions: Deploy to function app....

  2. Escolha o aplicativo de funções que você criou no primeiro artigo. Como você está reimplantando seu projeto no mesmo aplicativo, selecione Implantar para descartar o aviso de substituição de arquivos.

  3. Após a conclusão da implantação, use novamente o recurso Executar Função Agora... para disparar a função no Azure.

  4. Clique mais uma vez em Verificar os documentos criados no contêiner do Azure Cosmos DB para verificar se a associação de saída vai gerar um documento JSON novamente.

Limpar os recursos

No Azure, os Recursos se referem a aplicativos de funções, funções, contas de armazenamento e assim por diante. Eles são agrupados em grupos de recursos e você pode excluir tudo junto ao excluir o grupo.

Você criou recursos para concluir esses guias de início rápido. Esses recursos podem ser cobrados, dependendo do status da sua conta e do preço do serviço. Caso não precise mais dos recursos, é possível excluí-los desta maneira:

  1. No Visual Studio Code, pressione F1 para abrir a paleta de comandos. Na paleta de comandos, pesquise e selecione Azure: Open in portal.

  2. Escolha seu aplicativo de funções e pressione ENTER. A página do aplicativo de funções é aberta no portal do Azure.

  3. Na guia Visão geral, selecione o link nomeado ao lado de Grupo de recursos.

    Captura de tela de seleção do grupo de recursos para excluir da página do aplicativo de funções.

  4. Na página Grupo de recursos, revise a lista de recursos incluídos e verifique se eles são aqueles que você deseja excluir.

  5. Selecione Excluir grupo de recursos e siga as instruções.

    A exclusão poderá levar alguns minutos. Ao ser concluída, uma notificação será exibida por alguns segundos. Também é possível selecionar o ícone de sino na parte superior da página para exibir a notificação.

Próximas etapas

Você atualizou uma função disparada por HTTP para gravar documentos JSON em um contêiner do Azure Cosmos DB. Agora você pode saber mais sobre o desenvolvimento no Functions usando o Visual Studio Code: