{"id":2530,"date":"2023-03-08T08:02:07","date_gmt":"2023-03-08T16:02:07","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sdk\/?p=2530"},"modified":"2023-03-08T08:02:07","modified_gmt":"2023-03-08T16:02:07","slug":"announcing-the-stable-release-of-the-azure-blob-storage-client-library-for-go","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sdk\/announcing-the-stable-release-of-the-azure-blob-storage-client-library-for-go\/","title":{"rendered":"Announcing the stable release of the Azure Blob Storage client library for Go"},"content":{"rendered":"<p>The Azure SDK for Go team at Microsoft is excited to announce the stable release of the <a href=\"https:\/\/pkg.go.dev\/github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\">Azure Blob Storage client library for Go<\/a>. <a href=\"https:\/\/azure.microsoft.com\/products\/storage\/blobs\/\">Azure Blob Storage<\/a> is a secure object storage solution for the cloud. Azure Blob Storage is optimized for storing massive amounts of unstructured data\u2014data that doesn&#8217;t adhere to a particular data model or definition, such as text or binary data.<\/p>\n<blockquote><p>NOTE: If you&#8217;re using the legacy <a href=\"https:\/\/github.com\/Azure\/azure-storage-blob-go\">Azure Blob Storage library for Go<\/a> and would like to upgrade, see the <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-go\/blob\/main\/sdk\/storage\/azblob\/migrationguide.md\">migration guide<\/a>.<\/p><\/blockquote>\n<h2>Install the package<\/h2>\n<p>The Azure Blob Storage client library is named <code>azblob<\/code>. To install the latest version of <code>azblob<\/code>, use the <code>go get<\/code> command. You can use the Azure Identity library to authenticate the client application.<\/p>\n<pre><code class=\"language-bash\">go get github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\r\n\r\n# Optionally, if you also want to use Azure Identity for authentication\r\ngo get github.com\/Azure\/azure-sdk-for-go\/sdk\/azidentity<\/code><\/pre>\n<p>We assume that you have:<\/p>\n<ul>\n<li>An Azure subscription with an Azure Blob Storage container.<\/li>\n<li>A working development environment for Go version 1.18 or above.<\/li>\n<\/ul>\n<p>For instructions on creating an Azure Blob Storage container, follow this <a href=\"https:\/\/learn.microsoft.com\/azure\/storage\/blobs\/storage-quickstart-blobs-portal\">step-by-step guide<\/a>.<\/p>\n<h2>Create a client<\/h2>\n<p><code>Client<\/code> is a type that exposes methods that invoke service operations. A single <code>Client<\/code> type is shareable between multiple goroutines simultaneously and safely.<\/p>\n<p>Azure Blob storage service offers three types of resources, the storage account that has one or more containers and one or more blobs in a container. Instances of the <code>azblob.Client<\/code> type provide methods to manipulate containers and blobs within a storage account. You must specify the storage account when you create <code>azblob.Client<\/code>.<\/p>\n<p>You can create a client using an Azure Blob Storage connection string (obtained via the Azure portal) or with a <code>TokenCredential<\/code> type, such as <code>DefaultAzureCredential<\/code> from the Azure Identity library.<\/p>\n<blockquote><p>NOTE: We recommend you to use <code>TokenCredential<\/code> type for authentication, connection string authentication is not recommended.<\/p><\/blockquote>\n<h3>Use the <code>DefaultAzureCredential<\/code> token credential (Recommended)<\/h3>\n<p>The <code>DefaultAzureCredential<\/code> combines several credential types into one easy-to-use type. It can authenticate using the Azure CLI, managed identities, and more. For more information, see the <a href=\"https:\/\/pkg.go.dev\/github.com\/Azure\/azure-sdk-for-go\/sdk\/azidentity#section-readme\"><code>azidentity<\/code> documentation<\/a>.<\/p>\n<pre><code class=\"language-go\">import (\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/azidentity\"\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\"\r\n)\r\n\r\nfunc main() {\r\n    tokenCredential, err := azidentity.NewDefaultAzureCredential(nil)\r\n    if err != nil {\r\n        \/\/TODO: handle error\r\n        panic(err)\r\n    }\r\n\r\n    client, err := azblob.NewClient(\"&lt;Azure Storage URL ex: https:\/\/my-blob.blob.core.windows.net\/&gt;\", tokenCredential, nil)\r\n    if err != nil {\r\n        \/\/TODO: handle error\r\n        panic(err)\r\n    }\r\n}<\/code><\/pre>\n<h3>Use Azure Blob Storage connection string<\/h3>\n<p>Azure Blob Storage also supports authentication using a connection string, which you can get from the Azure portal.<\/p>\n<pre><code class=\"language-go\">package main\r\n\r\nimport (\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\"\r\n)\r\n\r\nfunc main() {\r\n    serviceClient, err := azblob.NewClientFromConnectionString(\"&lt;Azure Storage Connection String&gt;\", nil)\r\n    if err != nil {\r\n        \/\/TODO: handle error\r\n        panic(err)\r\n    }\r\n}<\/code><\/pre>\n<h2>Container operations<\/h2>\n<p>The <code>azblob.Client<\/code> type exposes container operations that manipulate the lifecycle of the Azure Storage container.<\/p>\n<h3>Create a container<\/h3>\n<p><code>CreateContainer<\/code> is a method that creates a new container under the specified account. This method returns a client for interacting with the newly created container. If a container with the same name already exists, the method call raises a <code>ResourceExistsError<\/code>.<\/p>\n<pre><code class=\"language-go\">import (\r\n    \"context\"\r\n    \"fmt\"\r\n    \"log\"\r\n    \"os\"\r\n\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/azcore\/to\"\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/azidentity\"\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\"\r\n)\r\n\r\nfunc handleError(err error) {\r\n    if err != nil {\r\n        log.Fatal(err.Error())\r\n    }\r\n}\r\n\r\nfunc main() {\r\n    accountName, ok := os.LookupEnv(\"AZURE_STORAGE_ACCOUNT_NAME\")\r\n    if !ok {\r\n        panic(\"AZURE_STORAGE_ACCOUNT_NAME could not be found\")\r\n    }\r\n    serviceURL := fmt.Sprintf(\"https:\/\/%s.blob.core.windows.net\/\", accountName)\r\n\r\n    cred, err := azidentity.NewDefaultAzureCredential(nil)\r\n    handleError(err)\r\n\r\n    client, err := azblob.NewClient(serviceURL, cred, nil)\r\n    handleError(err)\r\n\r\n    resp, err := client.CreateContainer(context.TODO(), \"testcontainer\", &amp;azblob.CreateContainerOptions{\r\n        Metadata: map[string]*string{\"hello\": to.Ptr(\"world\")},\r\n    })\r\n    handleError(err)\r\n    fmt.Println(resp)\r\n}<\/code><\/pre>\n<h3>Delete a container<\/h3>\n<p><code>DeleteContainer<\/code> is a container lifecycle method that marks the specified container for deletion. During garbage collection, Azure deletes the container and any blobs within it. If the container is missing, the method call raises a <code>ResourceNotFoundError<\/code>.<\/p>\n<pre><code class=\"language-go\">package main\r\n\r\nimport (\r\n    \"context\"\r\n    \"fmt\"\r\n    \"log\"\r\n    \"os\"\r\n\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/azidentity\"\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\"\r\n)\r\n\r\nfunc handleError(err error) {\r\n    if err != nil {\r\n        log.Fatal(err.Error())\r\n    }\r\n}\r\n\r\nfunc main() {\r\n    accountName, ok := os.LookupEnv(\"AZURE_STORAGE_ACCOUNT_NAME\")\r\n    if !ok {\r\n        panic(\"AZURE_STORAGE_ACCOUNT_NAME could not be found\")\r\n    }\r\n    serviceURL := fmt.Sprintf(\"https:\/\/%s.blob.core.windows.net\/\", accountName)\r\n\r\n    cred, err := azidentity.NewDefaultAzureCredential(nil)\r\n    handleError(err)\r\n\r\n    client, err := azblob.NewClient(serviceURL, cred, nil)\r\n    handleError(err)\r\n\r\n    resp, err := client.DeleteContainer(context.TODO(), \"testcontainer\", nil)\r\n    handleError(err)\r\n    fmt.Println(resp)\r\n}<\/code><\/pre>\n<h2>Blob operations<\/h2>\n<p>The <code>azblob.Client<\/code> type exposes these operations that interact with the blobs that reside inside the Azure Storage container. These operations require a valid Azure Storage container name that you pass as a parameter.<\/p>\n<h3>Upload blob to a container<\/h3>\n<p><code>UploadFile<\/code> uploads a file in blocks to a blob inside the Azure Storage container that you pass as a parameter.<\/p>\n<pre><code class=\"language-go\">package main\r\n\r\nimport (\r\n    \"context\"\r\n    \"fmt\"\r\n    \"log\"\r\n    \"os\"\r\n\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/azidentity\"\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\"\r\n)\r\n\r\nfunc handleError(err error) {\r\n    if err != nil {\r\n        log.Fatal(err.Error())\r\n    }\r\n}\r\n\r\nfunc main() {\r\n    \/\/ Set up file to upload\r\n    fileSize := 8 * 1024 * 1024\r\n    fileName := \"test_upload_file.txt\"\r\n    fileData := make([]byte, fileSize)\r\n    err := os.WriteFile(fileName, fileData, 0666)\r\n    handleError(err)\r\n\r\n    \/\/ Open the file to upload\r\n    fileHandler, err := os.Open(fileName)\r\n    handleError(err)\r\n\r\n    \/\/ close the file after it is no longer required.\r\n    defer func(file *os.File) {\r\n        err = file.Close()\r\n        handleError(err)\r\n    }(fileHandler)\r\n\r\n    \/\/ delete the local file if required.\r\n    defer func(name string) {\r\n        err = os.Remove(name)\r\n        handleError(err)\r\n    }(fileName)\r\n\r\n    accountName, ok := os.LookupEnv(\"AZURE_STORAGE_ACCOUNT_NAME\")\r\n    if !ok {\r\n        panic(\"AZURE_STORAGE_ACCOUNT_NAME could not be found\")\r\n    }\r\n    serviceURL := fmt.Sprintf(\"https:\/\/%s.blob.core.windows.net\/\", accountName)\r\n\r\n    cred, err := azidentity.NewDefaultAzureCredential(nil)\r\n    handleError(err)\r\n\r\n    client, err := azblob.NewClient(serviceURL, cred, nil)\r\n    handleError(err)\r\n\r\n    \/\/ Upload the file to a block blob\r\n    _, err = client.UploadFile(context.TODO(), \"testcontainer\", \"virtual\/dir\/path\/\"+fileName, fileHandler,\r\n        &amp;azblob.UploadFileOptions{\r\n            BlockSize:   int64(1024),\r\n            Concurrency: uint16(3),\r\n            \/\/ If Progress is non-nil, this function is called periodically as bytes are uploaded.\r\n            Progress: func(bytesTransferred int64) {\r\n                fmt.Println(bytesTransferred)\r\n            },\r\n        })\r\n    handleError(err)\r\n}<\/code><\/pre>\n<h3>Download blob from a container<\/h3>\n<p><code>DownloadFile<\/code> downloads a blob from the Azure Storage container that you pass as a parameter to a local file. If the size doesn&#8217;t match, the method truncates the destination file.<\/p>\n<pre><code class=\"language-go\">package main\r\n\r\nimport (\r\n    \"context\"\r\n    \"fmt\"\r\n    \"log\"\r\n    \"os\"\r\n\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/azidentity\"\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\"\r\n)\r\n\r\nfunc handleError(err error) {\r\n    if err != nil {\r\n        log.Fatal(err.Error())\r\n    }\r\n}\r\n\r\nfunc main() {\r\n    \/\/ Set up file to download the blob to\r\n    destFileName := \"test_download_file.txt\"\r\n    destFile, err := os.Create(destFileName)\r\n    handleError(err)\r\n    defer func(destFile *os.File) {\r\n        err = destFile.Close()\r\n        handleError(err)\r\n    }(destFile)\r\n\r\n    accountName, ok := os.LookupEnv(\"AZURE_STORAGE_ACCOUNT_NAME\")\r\n    if !ok {\r\n        panic(\"AZURE_STORAGE_ACCOUNT_NAME could not be found\")\r\n    }\r\n    serviceURL := fmt.Sprintf(\"https:\/\/%s.blob.core.windows.net\/\", accountName)\r\n\r\n    cred, err := azidentity.NewDefaultAzureCredential(nil)\r\n    handleError(err)\r\n\r\n    client, err := azblob.NewClient(serviceURL, cred, nil)\r\n    handleError(err)\r\n\r\n    \/\/ Perform download\r\n\r\n    _, err = client.DownloadFile(context.TODO(), \"testcontainer\", \"virtual\/dir\/path\/\"+destFileName, destFile,\r\n        &amp;azblob.DownloadFileOptions{\r\n            \/\/ If Progress is non-nil, this function is called periodically as bytes are uploaded.\r\n            Progress: func(bytesTransferred int64) {\r\n                fmt.Println(bytesTransferred)\r\n            },\r\n        })\r\n\r\n    \/\/ Assert download was successful\r\n    handleError(err)\r\n}<\/code><\/pre>\n<h3>Delete blob in a container<\/h3>\n<p><code>DeleteBlob<\/code> marks the specified blob or snapshot in the Azure Storage container for deletion. Azure deletes the blob later during garbage collection. Deleting a blob also deletes all its snapshots. For more information, see the <a href=\"https:\/\/learn.microsoft.com\/rest\/api\/storageservices\/delete-blob\">delete blob documentation<\/a>.<\/p>\n<pre><code class=\"language-go\">import (\r\n    \"context\"\r\n    \"fmt\"\r\n    \"log\"\r\n    \"os\"\r\n\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/azidentity\"\r\n    \"github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob\"\r\n)\r\n\r\nfunc handleError(err error) {\r\n    if err != nil {\r\n        log.Fatal(err.Error())\r\n    }\r\n}\r\n\r\nfunc main() {\r\n    accountName, ok := os.LookupEnv(\"AZURE_STORAGE_ACCOUNT_NAME\")\r\n    if !ok {\r\n        panic(\"AZURE_STORAGE_ACCOUNT_NAME could not be found\")\r\n    }\r\n    serviceURL := fmt.Sprintf(\"https:\/\/%s.blob.core.windows.net\/\", accountName)\r\n\r\n    cred, err := azidentity.NewDefaultAzureCredential(nil)\r\n    handleError(err)\r\n\r\n    client, err := azblob.NewClient(serviceURL, cred, nil)\r\n    handleError(err)\r\n\r\n    resp, err := client.DeleteBlob(context.TODO(), \"testcontainer\", \"testblob\", nil)\r\n    handleError(err)\r\n    fmt.Println(resp)\r\n}<\/code><\/pre>\n<h2>Summary<\/h2>\n<p>The Azure Blob Storage for Go library allows users to manipulate blobs and containers in Azure Storage. To learn more, see our <a href=\"https:\/\/pkg.go.dev\/github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob#section-readme\">documentation<\/a>. You can also find more examples either on <a href=\"https:\/\/pkg.go.dev\/github.com\/Azure\/azure-sdk-for-go\/sdk\/storage\/azblob#pkg-examples\">pkg.go.dev<\/a> or in our <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-go\/tree\/main\/sdk\/storage\/azblob\">GitHub repository<\/a>.<\/p>\n<h2>Feedback<\/h2>\n<p>We&#8217;d love to hear about your experiences using the Azure SDK for Go. Send us your feedback on our <a href=\"https:\/\/gophers.slack.com\/archives\/CA7HK8EEP\">Slack Channel<\/a> or at the <a href=\"https:\/\/discordapp.com\/channels\/723347736853741589\/933781546815606885\">#golang-friends<\/a> channel on the Microsoft Open Source Discord Server.<\/p>\n<p>For feature requests, bug reports, or general support, <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-go\/issues\/new\/choose\">open an issue<\/a> in the Azure SDK for Go repository on GitHub. For more information on how we triage issues, see the <a href=\"https:\/\/devblogs.microsoft.com\/azure-sdk\/github-issue-support-process\/\">Azure SDK GitHub Issue Support Process<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Announcing the stable release of Azure Blob Storage client library for Go<\/p>\n","protected":false},"author":91679,"featured_media":2551,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[892,893,810,811,24],"class_list":["post-2530","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sdk","tag-azure-storage-blob","tag-blob","tag-go","tag-golang","tag-releases"],"acf":[],"blog_post_summary":"<p>Announcing the stable release of Azure Blob Storage client library for Go<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/2530","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/users\/91679"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/comments?post=2530"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/2530\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media\/2551"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media?parent=2530"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/categories?post=2530"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/tags?post=2530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}