1
2# Azure Go Management SDK Guideline
3
4Azure Go management SDK follows the [new Azure SDK guidelines](https://azure.github.io/azure-sdk/general_introduction.html), try to create easy-to-use APIs that are idiomatic, compatible, and dependable.
5
6You can find the full list of management modules [here](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk).
7
8In this guideline, we will give some instructions about the API usage pattern as well as trouble shooting method. For those are new to management Go SDK, please refer to [quickstart](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/new-version-quickstart.md). For those migrate from older versions of management Go SDK, please refer to [migration guide](https://aka.ms/azsdk/go/mgmt/migration).
9
10## Pageable Operations
11
12### General usage
13
14Pageable operations return final data over multiple GET requests. Each GET will receive a page of data consisting of a slice of items. You need to use New*Pager to create a pager helper for all pageable operations. With the returned `*runtime.Pager[T]`, you can fetch pages and determine if there are more pages to fetch. For examples:
15
16```go
17import "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
18```
19
20```go
21ctx := context.TODO() // your context
22pager := rgClient.NewListPager(nil)
23var resourceGroups []*armresources.ResourceGroup
24for pager.More() {
25 nextResult, err := pager.NextPage(ctx)
26 if err != nil {
27 // handle error...
28 }
29 if nextResult.ResourceGroupListResult.Value != nil {
30 resourceGroups = append(resourceGroups, nextResult.ResourceGroupListResult.Value...)
31 }
32}
33// dealing with `resourceGroups`
34```
35
36> NOTE: No IO calls are made until the NextPage() method is invoked. The read consistency across pages is determined by the service implement.
37
38### Reference
39
40For more information, you can refer to [design guidelines of Paging](https://azure.github.io/azure-sdk/golang_introduction.html#methods-returning-collections-paging) and [API reference of pager](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime#Pager).
41
42## Long-Running Operations
43
44### General usage
45
46Some operations can take a long time to complete. Azure introduces the long-running operations (LROs) to do such operations asynchronously. You need to use Begin* to start an LRO. It will return a poller that can used to keep polling for the result until LRO is done. For examples:
47
48```go
49ctx := context.TODO() // your context
50poller, err := client.BeginCreate(ctx, "resource_identifier", "additonal_parameter", nil)
51if err != nil {
52 // handle error...
53}
54resp, err = poller.PollUntilDone(ctx, nil)
55if err != nil {
56 // handle error...
57}
58// dealing with `resp`
59```
60
61### Resume Tokens
62
63Pollers provide the ability to serialize their state into a "resume token" which can be used by another process to recreate the poller. For example:
64
65```go
66import "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
67```
68
69```go
70ctx := context.TODO() // your context
71poller, err := client.BeginCreate(ctx, "resource_identifier", "additonal_parameter", nil)
72if err != nil {
73 // handle error...
74}
75token, err := poller.ResumeToken()
76if err != nil {
77 // handle error...
78}
79
80// ...
81
82// recreate the poller from the token
83poller, err = client.BeginCreate(ctx, "", "", &armresources.ResourceGroupsClientBeginCreateOptions{
84 ResumeToken: token,
85})
86resp, err = poller.PollUntilDone(ctx, nil)
87if err != nil {
88 // handle error...
89}
90// dealing with `resp`
91```
92
93> NOTE: A token can only be obtained for a poller that's not in `Succeeded`, `Failed` or `Canceled` state. Each time you call `poller.Poll()`, the token might change because of the LRO state's change. So if you need to cache the token for crash consistency, you need to update the cache when calling `poller.Poll()`.
94
95### Synchronized wrapper
96
97If you do not care about the underlaying detail about the LRO, you can use the following generic utility to create an synchronized wrapper for all LRO.
98
99> NOTE: The error return of `Wait` includes the error of starting LRO and error of interval polling. Also, the wrapper will hide the `poller` which means you cannot recovery from an LRO accidentally interrupt.
100
101***Synchronized wrapper utility***
102
103```go
104import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
105```
106
107```go
108type OperationWaiter[TResult any] struct {
109 poller *runtime.Poller[TResult]
110 err error
111}
112
113func (ow OperationWaiter[TResult]) Wait(ctx context.Context, freq time.Duration) (TResult, error) {
114 if ow.err != nil {
115 return *new(TResult), ow.err
116 }
117 return ow.poller.PollUntilDone(ctx, freq)
118}
119
120func NewOperationWaiter[TResult any](poller *runtime.Poller[TResult], err error) OperationWaiter[TResult] {
121 return OperationWaiter[TResult]{poller: poller, err: err}
122}
123```
124
125***Usage***
126
127```go
128ctx := context.TODO() // your context
129resp, err := NewOperationWaiter(client.BeginCreate(ctx, "resource_identifier", "additonal_parameter", nil)).Wait(ctx, time.Second)
130// dealing with `resp`
131```
132### Reference
133
134For more information, you can refer to [design guidelines of LRO](https://azure.github.io/azure-sdk/golang_introduction.html#methods-invoking-long-running-operations) and [API reference of poller](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime#Poller).
135
136## Client Options
137
138### Request Retry Policy
139The SDK provides a baked in retry policy for failed requests with default values that can be configured by `arm.ClientOptions.Retry`. For example:
140
141```go
142import "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
143import "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
144import "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
145```
146
147```go
148rgClient, err := armresources.NewResourceGroupsClient(subscriptionId, credential,
149 &arm.ClientOptions{
150 ClientOptions: policy.ClientOptions{
151 Retry: policy.RetryOptions{
152 // retry for 5 times
153 MaxRetries: 5,
154 },
155 },
156 },
157)
158```
159
160### Customized Policy
161
162You can use `arm.ClientOptions.PerCallPolicies` and `arm.ClientOptions.PerRetryPolicies` option to inject customized policies to the pipeline. You can refer to `azcore` [document](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azcore) for further information.
163
164### Custom HTTP Client
165
166You can use `arm.ClientOptions.Transport` to set your own implementation of HTTP client. The HTTP client must implement the `policy.Transporter` interface. For example:
167
168```go
169import "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
170import "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
171import "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
172```
173
174```go
175// your own implementation of HTTP client
176httpClient := NewYourOwnHTTPClient{}
177rgClient, err := armresources.NewResourceGroupsClient(subscriptionId, credential,
178 &arm.ClientOptions{
179 ClientOptions: policy.ClientOptions{
180 Transport: &httpClient,
181 },
182 },
183)
184```
185
186### Reference
187
188More client options can be found [here](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/azcore/policy/policy.go).
189
190
191## Troubleshooting
192
193### Logging
194
195The SDK uses the classification-based logging implementation in `azcore`. To enable console logging for all SDK modules, please set environment variable `AZURE_SDK_GO_LOGGING` to `all`.
196
197You can use `policy.LogOption` to configure the logging behavior. For example:
198
199```go
200import "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
201import "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
202import "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
203```
204
205```go
206rgClient, err := armresources.NewResourceGroupsClient(subscriptionId, credential,
207 &arm.ClientOptions{
208 ClientOptions: policy.ClientOptions{
209 Logging: policy.LogOptions{
210 // include HTTP body for log
211 IncludeBody: true,
212 },
213 },
214 },
215)
216```
217
218You could use the `azcore/log` package to control log event and redirect log to the desired location. For example:
219
220```go
221import azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"
222import "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
223```
224
225```go
226// print log output to stdout
227azlog.SetListener(func(event azlog.Event, s string) {
228 fmt.Println(s)
229})
230
231// include only azidentity credential logs
232azlog.SetEvents(azidentity.EventAuthentication)
233```
234
235### Raw HTTP response
236
237- You can always get the raw HTTP response from request context regardless of request result.
238
239```go
240import "github.com/Azure/azure-sdk-for-go/sdk/azcore"
241import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
242```
243
244```go
245var rawResponse *http.Response
246ctx := context.TODO() // your context
247ctxWithResp := runtime.WithCaptureResponse(ctx, &rawResponse)
248resp, err := resourceGroupsClient.CreateOrUpdate(ctxWithResp, resourceGroupName, resourceGroupParameters, nil)
249if err != nil {
250 log.Printf("Status code: %d", rawResponse.StatusCode)
251 log.Fatalf("Error occurred: %+v", err)
252}
253log.Printf("Status code: %d", rawResponse.StatusCode)
254```
255
256- When there is an error in the SDK request, you can also convert the error to the `azcore.ResponseError` interface to get the raw HTTP response.
257
258```go
259import "github.com/Azure/azure-sdk-for-go/sdk/azcore"
260import "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
261```
262
263```go
264ctx := context.TODO() // your context
265resp, err := resourceGroupsClient.CreateOrUpdate(ctx, resourceGroupName, resourceGroupParameters, nil)
266if err != nil {
267 var respErr *azcore.ResponseError
268 if errors.As(err, &respErr) {
269 log.Fatalf("Status code: %d", respErr.RawResponse.StatusCode)
270 } else {
271 log.Fatalf("Other error: %+v", err)
272 }
273}
274// dealing with `resp`
275```
276
277## Need help?
278
279- File an issue via [Github Issues](https://github.com/Azure/azure-sdk-for-go/issues)
280- Check [previous questions](https://stackoverflow.com/questions/tagged/azure+go) or ask new ones on StackOverflow using azure and Go tags.
281
282## Contributing
283
284For details on contributing to this repository, see the [contributing guide](https://github.com/Azure/azure-sdk-for-go/blob/main/CONTRIBUTING.md).
285
286This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, please visit https://cla.microsoft.com.
287
288When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the
289bot. You will only need to do this once across all repositories using our CLA.
290
291This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any questions or comments.
View as plain text