Mulai cepat: Membangun aplikasi Go menggunakan akun API SQL Azure Cosmos DB

BERLAKU UNTUK: SQL API

Dalam mulai cepat ini, Anda akan membangun contoh aplikasi Go yang menggunakan SDK Azure untuk Go guna mengelola akun API SQL Cosmos DB.

Microsoft Azure Cosmos DB adalah layanan database multi-model yang memungkinkan Anda membuat dan mengkueri dokumen, tabel, nilai-kunci, dan database grafik dengan kemampuan distribusi global dan skala horizontal dengan cepat.

Untuk mempelajari selengkapnya tentang Azure Cosmos DB, buka Azure Cosmos DB.

Prasyarat

Memulai

Untuk mulai cepat ini, Anda harus membuat grup sumber daya Azure dan akun Cosmos DB.

Jalankan perintah berikut ini untuk membuat grup sumber daya Azure:

az group create --name myResourceGroup --location eastus

Selanjutnya buat akun Cosmos DB dengan menjalankan perintah berikut:

az cosmosdb create --name my-cosmosdb-account --resource-group myResourceGroup

Instal paket

Gunakan perintah go get untuk menginstal paket azcosmos.

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

Konsep utama

  • Client adalah koneksi ke akun Azure Cosmos DB.
  • Akun Azure Cosmos DB dapat memiliki beberapa databases. DatabaseClient memungkinkan Anda membuat, membaca, dan menghapus database.
  • Database dalam Akun Azure Cosmos dapat memiliki beberapa containers. ContainerClient memungkinkan Anda membuat, membaca, memperbarui, dan menghapus kontainer, serta mengubah ketentuan throughput.
  • Informasi disimpan sebagai item di dalam kontainer. Dan klien memungkinkan Anda membuat, membaca, memperbarui, dan menghapus item dalam kontainer.

Contoh kode

Autentikasi klien

var endpoint = "<azure_cosmos_uri>"
var key      = "<azure_cosmos_primary_key"

cred, err := azcosmos.NewKeyCredential(key)
if err != nil {
    log.Fatal("Failed to create a credential: ", err)
}

// Create a CosmosDB client
client, err := azcosmos.NewClientWithKey(endpoint, cred, nil)
if err != nil {
    log.Fatal("Failed to create cosmos client: ", err)
}

// Create database client
databaseClient, err := client.NewDatabase("<databaseName>")
if err != nil {
    log.Fatal("Failed to create database client:", err)
}

// Create container client
containerClient, err := client.NewContainer("<databaseName>", "<containerName>")
if err != nil {
    log.Fatal("Failed to create a container client:", err)
}

Membuat database Cosmos DB

import (
	"context"
	"log"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func createDatabase (client *azcosmos.Client, databaseName string) error {
//	databaseName := "adventureworks"

	// sets the name of the database
	databaseProperties := azcosmos.DatabaseProperties{ID: databaseName}

	// creating the database
	ctx := context.TODO()
	databaseResp, err := client.CreateDatabase(ctx, databaseProperties, nil)
	if err != nil {
		log.Fatal(err)
	}
	return nil
}

Membuat kontainer

import (
	"context"
	"log"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func createContainer (client *azcosmos.Client, databaseName, containerName, partitionKey string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "/customerId"
	
	databaseClient, err := client.NewDatabase(databaseName) // returns a struct that represents a database
	if err != nil {
		log.Fatal("Failed to create a database client:", err)
	}

	// Setting container properties
	containerProperties := azcosmos.ContainerProperties{
		ID: containerName,
		PartitionKeyDefinition: azcosmos.PartitionKeyDefinition{
			Paths: []string{partitionKey},
		},
	}

	// Setting container options 
	throughputProperties := azcosmos.NewManualThroughputProperties(400) //defaults to 400 if not set
	options := &azcosmos.CreateContainerOptions{
		ThroughputProperties: &throughputProperties,
	}

	ctx := context.TODO()
	containerResponse, err := databaseClient.CreateContainer(ctx, containerProperties, options)
	if err != nil {
		log.Fatal(err)

	}
	log.Printf("Container [%v] created. ActivityId %s\n", containerName, containerResponse.ActivityID)
	
	return nil
}

Membuat item

import (
	"context"
	"log"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func createItem(client *azcosmos.Client, databaseName, containerName, partitionKey string, item any) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
/*
	item = struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{
		ID:           "1",
		CustomerId:   "1",
		Title:        "Mr",
		FirstName:    "Luke",
		LastName:     "Hayes",
		EmailAddress: "luke12@adventure-works.com",
		PhoneNumber:  "879-555-0197",
	}
*/
	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("failed to create a container client: %s", err)
	}

	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	b, err := json.Marshal(item)
	if err != nil {
		return err
	}
	// setting item options upon creating ie. consistency level
	itemOptions := azcosmos.ItemOptions{
		ConsistencyLevel: azcosmos.ConsistencyLevelSession.ToPtr(),
	}
	ctx := context.TODO()
	itemResponse, err := containerClient.CreateItem(ctx, pk, b, &itemOptions)

	if err != nil {
		return err
	}
	log.Printf("Status %d. Item %v created. ActivityId %s. Consuming %v Request Units.\n", itemResponse.RawResponse.StatusCode, pk, itemResponse.ActivityID, itemResponse.RequestCharge)

	return nil
}

Membaca item

import (
	"context"
	"log"
	"fmt"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func readItem(client *azcosmos.Client, databaseName, containerName, partitionKey, itemId string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
//	itemId = "1"

	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("Failed to create a container client: %s", err)
	}

	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	// Read an item
	ctx := context.TODO()
	itemResponse, err := containerClient.ReadItem(ctx, pk, itemId, nil)
	if err != nil {
		return err
	}

	itemResponseBody := struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{}

	err = json.Unmarshal(itemResponse.Value, &itemResponseBody)
	if err != nil {
		return err
	}

	b, err := json.MarshalIndent(itemResponseBody, "", "    ")
	if err != nil {
		return err
	}
	fmt.Printf("Read item with customerId %s\n", itemResponseBody.CustomerId)
	fmt.Printf("%s\n", b)

	log.Printf("Status %d. Item %v read. ActivityId %s. Consuming %v Request Units.\n", itemResponse.RawResponse.StatusCode, pk, itemResponse.ActivityID, itemResponse.RequestCharge)

	return nil
}

Menghapus item

import (
	"context"
	"log"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func deleteItem(client *azcosmos.Client, databaseName, containerName, partitionKey, itemId string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
//	itemId = "1"

	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("Failed to create a container client: %s", err)
	}
	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	// Delete an item
	ctx := context.TODO()
	res, err := containerClient.DeleteItem(ctx, pk, itemId, nil)
	if err != nil {
		return err
	}

	log.Printf("Status %d. Item %v deleted. ActivityId %s. Consuming %v Request Units.\n", res.RawResponse.StatusCode, pk, res.ActivityID, res.RequestCharge)

	return nil
}

Menjalankan kode

Untuk mengautentikasi, Anda harus meneruskan kredensial akun Azure Cosmos ke aplikasi.

Dapatkan kredensial akun Azure Cosmos Anda dengan mengikuti langkah-langkah berikut:

  1. Masuk ke portal Azure.

  2. Arahkan ke akun Azure Cosmos Anda.

  3. Buka panel Kunci lalu salin URI dan KUNCI PRIMER akun Anda. Anda akan menambahkan nilai URI dan kunci ke variabel lingkungan di langkah berikutnya.

Setelah Anda menyalin URI dan KUNCI PRIMER akun Anda, simpan ke variabel lingkungan baru di komputer lokal yang menjalankan aplikasi.

Gunakan nilai yang disalin dari portal Azure untuk mengatur variabel lingkungan berikut:

export AZURE_COSMOS_ENPOINT=<Your_AZURE_COSMOS_URI>
export AZURE_COSMOS_KEY=<Your_COSMOS_PRIMARY_KEY>

Buat modul Go baru dengan menjalankan perintah berikut:

go mod init azcosmos

package main

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

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"
)

func main() {
	endpoint := os.Getenv("AZURE_COSMOS_ENDPOINT")
	if endpoint == "" {
		log.Fatal("AZURE_COSMOS_ENDPOINT could not be found")
	}

	key := os.Getenv("AZURE_COSMOS_KEY")
	if key == "" {
		log.Fatal("AZURE_COSMOS_KEY could not be found")
	}

	var databaseName = "adventureworks"
	var containerName = "customer"
	var partitionKey = "/customerId"

	item := struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{
		ID:           "1",
		CustomerId:   "1",
		Title:        "Mr",
		FirstName:    "Luke",
		LastName:     "Hayes",
		EmailAddress: "luke12@adventure-works.com",
		PhoneNumber:  "879-555-0197",
	}

	cred, err := azcosmos.NewKeyCredential(key)
	if err != nil {
		log.Fatal("Failed to create a credential: ", err)
	}

	// Create a CosmosDB client
	client, err := azcosmos.NewClientWithKey(endpoint, cred, nil)
	if err != nil {
		log.Fatal("Failed to create cosmos db client: ", err)
	}
	
	err = createDatabase(client, databaseName)
	if err != nil {
		log.Printf("createDatabase failed: %s\n", err)
	}

	err = createContainer(client, databaseName, containerName, partitionKey)
	if err != nil {
		log.Printf("createContainer failed: %s\n", err)
	}

	err = createItem(client, databaseName, containerName, item.CustomerId, item)
	if err != nil {
		log.Printf("createItem failed: %s\n", err)
	}

	err = readItem(client, databaseName, containerName, item.CustomerId, item.ID)
	if err != nil {
		log.Printf("readItem failed: %s\n", err)
	}
	
	err = deleteItem(client, databaseName, containerName, item.CustomerId, item.ID)
	if err != nil {
		log.Printf("deleteItem failed: %s\n", err)
	}
}

func createDatabase(client *azcosmos.Client, databaseName string) error {
//	databaseName := "adventureworks"

	databaseProperties := azcosmos.DatabaseProperties{ID: databaseName}

	// This is a helper function that swallows 409 errors
	errorIs409 := func(err error) bool {
		var responseErr *azcore.ResponseError
		return err != nil && errors.As(err, &responseErr) && responseErr.StatusCode == 409
	}
	ctx := context.TODO()
	databaseResp, err := client.CreateDatabase(ctx, databaseProperties, nil)

	switch {
	case errorIs409(err):
		log.Printf("Database [%s] already exists\n", databaseName)
	case err != nil:
		return err
	default:
		log.Printf("Database [%v] created. ActivityId %s\n", databaseName, databaseResp.ActivityID)
	}
	return nil
}

func createContainer(client *azcosmos.Client, databaseName, containerName, partitionKey string) error {
//	databaseName = adventureworks
//	containerName = customer
//	partitionKey = "/customerId"

	databaseClient, err := client.NewDatabase(databaseName)
	if err != nil {
		return err
	}

	// creating a container
	containerProperties := azcosmos.ContainerProperties{
		ID: containerName,
		PartitionKeyDefinition: azcosmos.PartitionKeyDefinition{
			Paths: []string{partitionKey},
		},
	}

	// this is a helper function that swallows 409 errors
	errorIs409 := func(err error) bool {
		var responseErr *azcore.ResponseError
		return err != nil && errors.As(err, &responseErr) && responseErr.StatusCode == 409
	}

	// setting options upon container creation
	throughputProperties := azcosmos.NewManualThroughputProperties(400) //defaults to 400 if not set
	options := &azcosmos.CreateContainerOptions{
		ThroughputProperties: &throughputProperties,
	}
	ctx := context.TODO()
	containerResponse, err := databaseClient.CreateContainer(ctx, containerProperties, options)
	
	switch {
	case errorIs409(err):
		log.Printf("Container [%s] already exists\n", containerName)
	case err != nil:
		return err
	default:
		log.Printf("Container [%s] created. ActivityId %s\n", containerName, containerResponse.ActivityID)
	}
	return nil
}

func createItem(client *azcosmos.Client, databaseName, containerName, partitionKey string, item any) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"

/*	item = struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{
		ID:           "1",
		CustomerId:   "1",
		Title:        "Mr",
		FirstName:    "Luke",
		LastName:     "Hayes",
		EmailAddress: "luke12@adventure-works.com",
		PhoneNumber:  "879-555-0197",
		CreationDate: "2014-02-25T00:00:00",
	}
*/
	// create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("failed to create a container client: %s", err)
	}

	// specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	b, err := json.Marshal(item)
	if err != nil {
		return err
	}
	// setting the item options upon creating ie. consistency level
	itemOptions := azcosmos.ItemOptions{
		ConsistencyLevel: azcosmos.ConsistencyLevelSession.ToPtr(),
	}

	// this is a helper function that swallows 409 errors
	errorIs409 := func(err error) bool {
		var responseErr *azcore.ResponseError
		return err != nil && errors.As(err, &responseErr) && responseErr.StatusCode == 409
	}

	ctx := context.TODO()
	itemResponse, err := containerClient.CreateItem(ctx, pk, b, &itemOptions)
	
	switch {
	case errorIs409(err):
		log.Printf("Item with partitionkey value %s already exists\n", pk)
	case err != nil:
		return err
	default:
		log.Printf("Status %d. Item %v created. ActivityId %s. Consuming %v Request Units.\n", itemResponse.RawResponse.StatusCode, pk, itemResponse.ActivityID, itemResponse.RequestCharge)
	}
	
	return nil
}

func readItem(client *azcosmos.Client, databaseName, containerName, partitionKey, itemId string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
//	itemId = "1"

	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("failed to create a container client: %s", err)
	}

	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	// Read an item
	ctx := context.TODO()
	itemResponse, err := containerClient.ReadItem(ctx, pk, itemId, nil)
	if err != nil {
		return err
	}

	itemResponseBody := struct {
		ID           string `json:"id"`
		CustomerId   string `json:"customerId"`
		Title        string
		FirstName    string
		LastName     string
		EmailAddress string
		PhoneNumber  string
		CreationDate string
	}{}

	err = json.Unmarshal(itemResponse.Value, &itemResponseBody)
	if err != nil {
		return err
	}

	b, err := json.MarshalIndent(itemResponseBody, "", "    ")
	if err != nil {
		return err
	}
	fmt.Printf("Read item with customerId %s\n", itemResponseBody.CustomerId)
	fmt.Printf("%s\n", b)

	log.Printf("Status %d. Item %v read. ActivityId %s. Consuming %v Request Units.\n", itemResponse.RawResponse.StatusCode, pk, itemResponse.ActivityID, itemResponse.RequestCharge)

	return nil
}

func deleteItem(client *azcosmos.Client, databaseName, containerName, partitionKey, itemId string) error {
//	databaseName = "adventureworks"
//	containerName = "customer"
//	partitionKey = "1"
//	itemId = "1"

	// Create container client
	containerClient, err := client.NewContainer(databaseName, containerName)
	if err != nil {
		return fmt.Errorf("failed to create a container client:: %s", err)
	}
	// Specifies the value of the partiton key
	pk := azcosmos.NewPartitionKeyString(partitionKey)

	// Delete an item
	ctx := context.TODO()

	res, err := containerClient.DeleteItem(ctx, pk, itemId, nil)
	if err != nil {
		return err
	}

	log.Printf("Status %d. Item %v deleted. ActivityId %s. Consuming %v Request Units.\n", res.RawResponse.StatusCode, pk, res.ActivityID, res.RequestCharge)

	return nil
}

Buat file baru bernama main.go dan salin kode dari contoh bagian di atas.

Jalankan perintah berikut untuk menjalankan aplikasi:

go run main.go

Membersihkan sumber daya

Setelah selesai dengan aplikasi dan akun Azure Cosmos DB, Anda dapat menghapus sumber daya Azure yang dibuat sehingga tidak dikenakan lebih banyak biaya. Untuk menghapus sumber daya:

  1. Di portal Azure, cari dan pilih Grup sumber daya.

  2. Dari daftar, pilih grup sumber daya yang Anda buat untuk mulai cepat ini.

    Pilih grup sumber daya yang akan dihapus

  3. Di panel Gambaran umum grup sumber daya, pilih Hapus grup sumber daya.

    Menghapus grup sumber daya

  4. Di jendela berikutnya, masukkan nama grup sumber daya yang akan dihapus, lalu pilih Hapus.

Langkah berikutnya

Dalam mulai cepat ini, Anda telah mempelajari cara membuat akun Azure Cosmos DB, membuat database, kontainer, dan entri item. Sekarang impor lebih banyak data ke akun Azure Cosmos DB Anda.

Mencoba melakukan perencanaan kapasitas untuk migrasi ke Azure Cosmos DB? Anda dapat menggunakan informasi tentang kluster database Anda yang ada saat ini untuk perencanaan kapasitas.