...

Text file src/github.com/Azure/azure-sdk-for-go/documentation/new-version-guideline.md

Documentation: github.com/Azure/azure-sdk-for-go/documentation

     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