API Implementation
This section describes guidelines for implementing Azure SDK client libraries. Please note that some of these guidelines are automatically enforced by code generation tools.
The Service Client
Service clients are the main starting points for developers calling Azure services with the Azure SDK. Each client library should have at least one client, so it’s easy to discover. The guidelines in this section describe patterns for the design of a service client.
Service Methods
Using azcore.Pipeline
Each supported language has an Azure Core library that contains common mechanisms for cross cutting concerns such as configuration and doing HTTP requests.
✅ DO use the HTTP pipeline component within azcore
library for communicating to service REST endpoints.
The HTTP pipeline consists of a HTTP transport that is wrapped by multiple policies. Each policy is a control point during which the pipeline can modify either the request and/or response. We prescribe a default set of policies to standardize how client libraries interact with Azure services. The order in the list is the most sensible order for implementation.
✅ DO implement the following policies in the HTTP pipeline:
- Telemetry
- Retry
- Authentication
- Response downloader
- Distributed tracing
- Logging
- The HTTP transport itself
☑️ YOU SHOULD use the policy implementations in Azure Core whenever possible. Do not try to “write your own” policy unless it is doing something unique to your service. If you need another option to an existing policy, engage with the [Architecture Board] to add the option.
Using azcore.Policy
Service Method Parameters
Parameter validation
Supporting Types
Model Types
Serialization
Constants as Enumerations
✅ DO define the enumeration’s type to match the type sent/received over-the-wire (string is the most common example).
✅ DO name all values with a prefix of the type’s name.
✅ DO place all values for an enumerated type within their own const
block, which is to immediately follow the type’s declaration.
✅ DO define a function named <EnumTypeName>Values()
that returns a slice containing all possible values for the enumeration.
// WidgetColor specifies a Widget's color from the list of possible values.
type WidgetColor string
const (
WidgetColorBlue WidgetColor = "blue"
WidgetColorGreen WidgetColor = "green"
WidgetColorRed WidgetColor = "red"
)
// PossibleWidgetColorValues returns a slice of possible values for WidgetColor.
func PossibleWidgetColorValues() []WidgetColor {
// ...
}
SDK Feature Implementation
Configuration
✅ DO use relevant global configuration settings either by default or when explicitly requested to by the user, for example by passing in a configuration object to a client constructor.
✅ DO allow different clients of the same type to use different configurations.
✅ DO allow consumers of your service clients to opt out of all global configuration settings at once.
✅ DO allow all global configuration settings to be overridden by client-provided options. The names of these options should align with any user-facing global configuration keys.
⛔️ DO NOT change behavior based on configuration changes that occur after the client is constructed. Hierarchies of clients inherit parent client configuration unless explicitly changed or overridden. Exceptions to this requirement are as follows:
- Log level, which must take effect immediately across the Azure SDK.
- Tracing on/off, which must take effect immediately across the Azure SDK.
Configuration via Environment Variables
✅ DO prefix Azure-specific environment variables with AZURE_
.
✔️ YOU MAY use client library-specific environment variables for portal-configured settings which are provided as parameters to your client library. This generally includes credentials and connection details. For example, Service Bus could support the following environment variables:
AZURE_SERVICEBUS_CONNECTION_STRING
AZURE_SERVICEBUS_NAMESPACE
AZURE_SERVICEBUS_ISSUER
AZURE_SERVICEBUS_ACCESS_KEY
Storage could support:
AZURE_STORAGE_ACCOUNT
AZURE_STORAGE_ACCESS_KEY
AZURE_STORAGE_DNS_SUFFIX
AZURE_STORAGE_CONNECTION_STRING
✅ DO get approval from the [Architecture Board] for every new environment variable.
✅ DO use this syntax for environment variables specific to a particular Azure service:
AZURE_<ServiceName>_<ConfigurationKey>
Where ServiceName is the canonical shortname without spaces, and ConfigurationKey refers to an unnested configuration key for that client library.
⛔️ DO NOT use non-alpha-numeric characters in your environment variable names with the exception of underscore. This ensures broad interoperability.
Logging
Client libraries must support robust logging mechanisms so that the consumer can adequately diagnose issues with the method calls and quickly determine whether the issue is in the consumer code, client library code, or service.
✅ DO use the Logger API provided within azcore
as the sole logging API throughout all client libraries.
✅ DO define constant classification strings using the azcore.LogClassification
type, then log using these values.
✅ DO log HTTP request line, response line, and all header/query parameter names.
⛔️ DO NOT log payloads or HTTP header/query parameter values that aren’t on the allow list. For header/query parameters not on the allow list use the value <REDACTED>
in place of the real value.
Distributed Tracing
✅ DO abstract the underlying tracing facility, allowing consumers to use the tracing implementation of their choice.
✅ DO create a new trace span for each API call. New spans must be children of the context that was passed in.
✅ DO use <package name>.<type name>.<method name>
as the name of the span.
✅ DO propagate tracing context on each outgoing service request through the appropriate headers to support a tracing service like Azure Monitor or ZipKin. This is generally done with the HTTP pipeline.