Como usar o SDK do Azure para linguagem Go com a Tabela do Azure

APLICA-SE AO: Table

Dica

O conteúdo deste artigo se aplica ao Armazenamento de Tabelas do Azure e ao Azure Cosmos DB for Table. A API for Table é uma oferta premium para armazenamento de tabelas que oferece tabelas com taxa de transferência otimizada, distribuição global e índices secundários automáticos.

Neste artigo, você aprenderá a criar, listar e excluir entidades da Tabela e das Tabelas do Azure com o SDK do Azure para linguagem Go.

A Tabela do Azure permite armazenar dados NoSQL estruturados na nuvem, fornecendo um repositório de atributo de chave com um design sem esquema. Como o armazenamento da Tabela do Azure não tem esquema, é fácil adaptar seus dados à medida que as necessidades de seu aplicativo evoluem. O acesso aos dados e à API da tabela é uma solução rápida e econômica para muitos aplicativos.

Você pode usar o armazenamento da Tabela ou o Azure Cosmos DB para armazenar conjuntos de dados flexíveis, como dados de usuário para aplicativos Web, catálogos de endereços, informações sobre dispositivos. Ou outros tipos de metadados que seu serviço exige. Você pode armazenar qualquer número de entidades em uma tabela e uma conta de armazenamento pode conter um número ilimitado de tabelas, até o limite de capacidade da conta de armazenamento.

Siga este artigo para saber como gerenciar o armazenamento da Tabela do Azure usando o SDK do Azure para linguagem Go.

Pré-requisitos

Configure seu ambiente

Para acompanhar este tutorial, você precisará de um grupo de recursos do Azure, uma conta de armazenamento e um recurso de tabela. Execute os seguintes comandos para configurar seu ambiente:

  1. Crie um grupo de recursos do Azure.

    az group create --name myResourceGroup --location eastus
    
  2. Em seguida, crie uma conta de armazenamento do Azure para sua nova Tabela do Azure.

    az storage account create --name <storageAccountName> --resource-group myResourceGroup --location eastus --sku Standard_LRS
    
  3. Criar um recurso de tabela.

    az storage table create --account-name <storageAccountName> --account-key 'storageKey' --name mytable
    

Instalar Pacotes

Você precisará de dois pacotes para gerenciar a Tabela do Azure com a linguagem Go: azidentity e aztables. O pacote azidentity fornece um modo de autenticar no Azure. E os pacotes aztables oferecem a capacidade de gerenciar o recurso de tabelas no Azure. Execute os seguintes comandos Go para instalar estes pacotes:

go get github.com/Azure/azure-sdk-for-go/sdk/data/aztables
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity

Para saber mais sobre diferentes métodos de autenticação no Azure, confira Autenticação do Azure com o SDK do Azure para linguagem Go.

Criar o aplicativo de exemplo

Depois de instalar os pacotes, você cria um aplicativo de exemplo que usa o SDK do Azure para linguagem Go para gerenciar a Tabela do Azure. Execute o comando go mod para criar um módulo chamado azTableSample.

go mod init azTableSample

Em seguida, crie um arquivo chamado main.go e copie o que está abaixo nele:

package main

import (
    "context"
    "encoding/json"
    "fmt"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
    "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    "github.com/Azure/azure-sdk-for-go/sdk/data/aztables"
)

type InventoryEntity struct {
    aztables.Entity
    Price       float32
    Inventory   int32
    ProductName string
    OnSale      bool
}

type PurchasedEntity struct {
    aztables.Entity
    Price float32
    ProductName string
    OnSale bool
}

func getClient() *aztables.Client {
    accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT environment variable not found")
    }

    tableName, ok := os.LookupEnv("AZURE_TABLE_NAME")
    if !ok {
        panic("AZURE_TABLE_NAME environment variable not found")
    }

    cred, err := azidentity.NewDefaultAzureCredential(nil)
    if err != nil {
        panic(err)
    }
    serviceURL := fmt.Sprintf("https://%s.table.core.windows.net/%s", accountName, tableName)
    client, err := aztables.NewClient(serviceURL, cred, nil)
    if err != nil {
        panic(err)
    }
    return client
}

func createTable(client *aztables.Client) {
    //TODO: Check access policy, Storage Blob Data Contributor role needed
    _, err := client.Create(context.TODO(), nil)
    if err != nil {
        panic(err)
    }
}

func addEntity(client *aztables.Client) {
    myEntity := InventoryEntity{
        Entity: aztables.Entity{
            PartitionKey: "pk001",
            RowKey:       "rk001",
        },
        Price:       3.99,
        Inventory:   20,
        ProductName: "Markers",
        OnSale:      false,
    }

    marshalled, err := json.Marshal(myEntity)
    if err != nil {
        panic(err)
    }

    _, err = client.AddEntity(context.TODO(), marshalled, nil) // TODO: Check access policy, need Storage Table Data Contributor role
    if err != nil {
        panic(err)
    }
}

func listEntities(client *aztables.Client) {
    listPager := client.List(nil)
    pageCount := 0
    for listPager.More() {
        response, err := listPager.NextPage(context.TODO())
        if err != nil {
            panic(err)
        }
        fmt.Printf("There are %d entities in page #%d\n", len(response.Entities), pageCount)
        pageCount += 1
    }
}

func queryEntity(client *aztables.Client) {
    filter := fmt.Sprintf("PartitionKey eq '%v' or RowKey eq '%v'", "pk001", "rk001")
    options := &aztables.ListEntitiesOptions{
        Filter: &filter,
        Select: to.StringPtr("RowKey,Price,Inventory,ProductName,OnSale"),
        Top:    to.Int32Ptr(15),
    }

    pager := client.List(options)
    for pager.More() {
        resp, err := pager.NextPage(context.Background())
        if err != nil {
            panic(err)
        }
        for _, entity := range resp.Entities {
            var myEntity PurchasedEntity 
            err = json.Unmarshal(entity, &myEntity)
            if err != nil {
                panic(err)
            }
            fmt.Println("Return custom type [PurchasedEntity]")
            fmt.Printf("Price: %v; ProductName: %v; OnSale: %v\n", myEntity.Price, myEntity.ProductName, myEntity.OnSale)
        }
    }
}

func deleteEntity(client *aztables.Client) {
    _, err := client.DeleteEntity(context.TODO(), "pk001", "rk001", nil)
    if err != nil {
        panic(err)
    }
}

func deleteTable(client *aztables.Client) {
    _, err := client.Delete(context.TODO(), nil)
    if err != nil {
        panic(err)
    }
}

func main() {

    fmt.Println("Authenticating...")
    client := getClient()

    fmt.Println("Creating a table...")
    createTable(client)

    fmt.Println("Adding an entity to the table...")
    addEntity(client)

    fmt.Println("Calculating all entities in the table...")
    listEntities(client)

    fmt.Println("Querying a specific entity...")
    queryEntity(client) 

    fmt.Println("Deleting an entity...")
    deleteEntity(client) 

    fmt.Println("Deleting a table...")
    deleteTable(client)
}

Importante

Verifique se a conta com a qual você se autenticou tem a política de acesso adequada para gerenciar sua conta de armazenamento do Azure. Para executar o código acima, sua conta precisa ter, no mínimo, a função Colaborador de Dados de Blob de Armazenamento e a função Colaborador de Dados da Tabela de Armazenamento.

Exemplos de código

Autenticar o cliente

// Lookup environment variables
accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT")
if !ok {
  panic("AZURE_STORAGE_ACCOUNT environment variable not found")
}

tableName, ok := os.LookupEnv("AZURE_TABLE_NAME")
if !ok {
  panic("AZURE_TABLE_NAME environment variable not found")
}

// Create a credential
cred, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
  panic(err)
}

// Create a table client
serviceURL := fmt.Sprintf("https://%s.table.core.windows.net/%s", accountName, tableName)
client, err := aztables.NewClient(serviceURL, cred, nil)
if err != nil {
  panic(err)
}

Criar uma tabela

// Create a table and discard the response
_, err := client.Create(context.TODO(), nil)
if err != nil {
  panic(err)
}

Criar uma entidade

// Define the table entity as a custom type
type InventoryEntity struct {
    aztables.Entity
    Price       float32
    Inventory   int32
    ProductName string
    OnSale      bool
}

// Define the entity values
myEntity := InventoryEntity{
    Entity: aztables.Entity{
        PartitionKey: "pk001",
        RowKey:       "rk001",
    },
    Price:       3.99,
    Inventory:   20,
    ProductName: "Markers",
    OnSale:      false,
}

// Marshal the entity to JSON
marshalled, err := json.Marshal(myEntity)
if err != nil {
    panic(err)
}

// Add the entity to the table
_, err = client.AddEntity(context.TODO(), marshalled, nil) // needs Storage Table Data Contributor role
if err != nil {
    panic(err)
}

Obter uma entidade

// Define the new custom type
type PurchasedEntity struct {
    aztables.Entity
    Price       float32
    ProductName string
    OnSale      bool
}

// Define the query filter and options
filter := fmt.Sprintf("PartitionKey eq '%v' or RowKey eq '%v'", "pk001", "rk001")
options := &aztables.ListEntitiesOptions{
    Filter: &filter,
    Select: to.StringPtr("RowKey,Price,Inventory,ProductName,OnSale"),
    Top:    to.Int32Ptr(15),
}

// Query the table for the entity
pager := client.List(options)
for pager.More() {
    resp, err := pager.NextPage(context.Background())
    if err != nil {
        panic(err)
    }
    for _, entity := range resp.Entities {
        var myEntity PurchasedEntity
        err = json.Unmarshal(entity, &myEntity)
        if err != nil {
            panic(err)
        }
        fmt.Println("Return custom type [PurchasedEntity]")
        fmt.Printf("Price: %v; ProductName: %v; OnSale: %v\n", myEntity.Price, myEntity.ProductName, myEntity.OnSale)
    }
}

Excluir uma entidade

_, err := client.DeleteEntity(context.TODO(), "pk001", "rk001", nil)
if err != nil {
  panic(err)
}

Excluir uma tabela

_, err := client.Delete(context.TODO(), nil)
if err != nil {
  panic(err)
}

Executar o código

Agora tudo o que resta é executar o aplicativo. Mas antes de fazer isso, você precisa configurar suas variáveis de ambiente. Crie duas variáveis de ambiente e defina-as com o valor apropriado usando os seguintes comandos:

export AZURE_STORAGE_ACCOUNT=<YourStorageAccountName> 
export AZURE_TABLE_NAME=<YourAzureTableName>

Em seguida, execute o seguinte comando go run para executar o aplicativo:

go run main.go

Limpar os recursos

Execute o seguinte comando para excluir o grupo de recursos e todos os recursos restantes:

az group delete --resource-group myResourceGroup

Próximas etapas

Neste início rápido, você aprendeu como criar uma conta do BD Cosmos do Azure, como criar uma tabela usando o Data Explorer e como executar um aplicativo. Agora você pode consultar os dados usando a API de Tabela.