How to use the Azure SDK for Go with Azure Table
APPLIES TO: Table
Tip
The content in this article applies to Azure Table storage and Azure Cosmos DB for Table. The API for Table is a premium offering for table storage that offers throughput-optimized tables, global distribution, and automatic secondary indexes.
In this article, you'll learn how to create, list, and delete Azure Tables and Table entities with the Azure SDK for Go.
Azure Table allows you to store structured NoSQL data in the cloud by providing you with a key attribute store with a schemaless design. Because Azure Table storage is schemaless, it's easy to adapt your data to the evolving needs of your applications. Access to table's data and API is a fast and cost-effective solution for many applications.
You can use the Table storage or the Azure Cosmos DB to store flexible datasets like user data for web applications, address books, device information. Or other types of metadata your service requires. You can store any number of entities in a table, and a storage account may contain any number of tables, up to the capacity limit of the storage account.
Follow this article to learn how to manage Azure Table storage using the Azure SDK for Go.
Prerequisites
- An Azure subscription - create one for free.
- Go installed: Version 1.17 or above
- Azure CLI
Set up your environment
To follow along with this tutorial you'll need an Azure resource group, a storage account, and a table resource. Run the following commands to set up your environment:
Create an Azure resource group.
az group create --name myResourceGroup --location eastus
Next create an Azure storage account for your new Azure Table.
az storage account create --name <storageAccountName> --resource-group myResourceGroup --location eastus --sku Standard_LRS
Create a table resource.
az storage table create --account-name <storageAccountName> --account-key 'storageKey' --name mytable
Install packages
You'll need two packages to manage Azure Table with Go; azidentity, and aztables. The azidentity
package provides you with a way to authenticate to Azure. And the aztables
packages give you the ability to manage the tables resource in Azure. Run the following Go commands to install these packages:
go get github.com/Azure/azure-sdk-for-go/sdk/data/aztables
go get github.com/Azure/azure-sdk-for-go/sdk/azidentity
To learn more about the ways to authenticate to Azure, check out Azure authentication with the Azure SDK for Go.
Create the sample application
Once you have the packages installed, you create a sample application that uses the Azure SDK for Go to manage Azure Table. Run the go mod
command to create a new module named azTableSample
.
go mod init azTableSample
Next, create a file called main.go
, then copy below into it:
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)
}
Important
Ensure that the account you authenticated with has the proper accces policy to manage your Azure storage account. To run the above code you're account needs to have at a minimum the Storage Blob Data Contributor role and the Storage Table Data Contributor role.
Code examples
Authenticate the client
// 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)
}
Create a table
// Create a table and discard the response
_, err := client.Create(context.TODO(), nil)
if err != nil {
panic(err)
}
Create an entity
// 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)
}
Get an entity
// 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)
}
}
Delete an entity
_, err := client.DeleteEntity(context.TODO(), "pk001", "rk001", nil)
if err != nil {
panic(err)
}
Delete a table
_, err := client.Delete(context.TODO(), nil)
if err != nil {
panic(err)
}
Run the code
All that's left is to run the application. But before you do that, you need to set up your environment variables. Create two environment variables and set them to the appropriate value using the following commands:
export AZURE_STORAGE_ACCOUNT=<YourStorageAccountName>
export AZURE_TABLE_NAME=<YourAzureTableName>
Next, run the following go run
command to run the app:
go run main.go
Clean up resources
Run the following command to delete the resource group and all its remaining resources:
az group delete --resource-group myResourceGroup
Next steps
In this quickstart, you've learned how to create an Azure Cosmos DB account, create a table using the Data Explorer, and run an app. Now you can query your data using the API for Table.