Skip to content

Commit 913f1fc

Browse files
committed
aws: Config refactor to use pointer for fields [breaking change]
This change refactors the SDK so that Config fields are pointers instead of values. Primarily this change fixes the bug preventing setting Config fields to the field's zero value when creating new service client instances. ```go svc := s3.New(&aws.Config{ Region: aws.String("us-west-2"), MaxRetries: aws.Int(10), }) ``` Additionally builder pattern `WithX` methods were added to Config. These methods can be chained so inline building of Config objects can be done without using pointers for the fields. ```go svc := s3.New(aws.NewConfig().WithRegion("us-west-2").WithMaxRetries(10)) ``` Fixes #157 Fixes #276 Fixes #124
1 parent 0a416b5 commit 913f1fc

26 files changed

+240
-194
lines changed

aws/config.go

Lines changed: 145 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,11 @@ const DefaultRetries = -1
3232
// You may modify this global structure to change all default configuration
3333
// in the SDK. Note that configuration options are copied by value, so any
3434
// modifications must happen before constructing a client.
35-
var DefaultConfig = &Config{
36-
Credentials: DefaultChainCredentials,
37-
Endpoint: "",
38-
Region: os.Getenv("AWS_REGION"),
39-
DisableSSL: false,
40-
HTTPClient: http.DefaultClient,
41-
LogHTTPBody: false,
42-
LogLevel: 0,
43-
Logger: os.Stdout,
44-
MaxRetries: DefaultRetries,
45-
DisableParamValidation: false,
46-
DisableComputeChecksums: false,
47-
S3ForcePathStyle: false,
48-
}
35+
var DefaultConfig = NewConfig().
36+
WithCredentials(DefaultChainCredentials).
37+
WithRegion(os.Getenv("AWS_REGION")).
38+
WithHTTPClient(http.DefaultClient).
39+
WithMaxRetries(DefaultRetries)
4940

5041
// A Config provides service configuration for service clients. By default,
5142
// all clients will use the {DefaultConfig} structure.
@@ -60,7 +51,7 @@ type Config struct {
6051
//
6152
// @note You must still provide a `Region` value when specifying an
6253
// endpoint for a client.
63-
Endpoint string
54+
Endpoint *string
6455

6556
// The region to send requests to. This parameter is required and must
6657
// be configured globally or on a per-client basis unless otherwise
@@ -69,11 +60,11 @@ type Config struct {
6960
//
7061
// @see http://docs.aws.amazon.com/general/latest/gr/rande.html
7162
// AWS Regions and Endpoints
72-
Region string
63+
Region *string
7364

7465
// Set this to `true` to disable SSL when sending requests. Defaults
7566
// to `false`.
76-
DisableSSL bool
67+
DisableSSL *bool
7768

7869
// The HTTP client to use when sending requests. Defaults to
7970
// `http.DefaultClient`.
@@ -84,12 +75,12 @@ type Config struct {
8475
//
8576
// @note `LogLevel` must be set to a non-zero value in order to activate
8677
// body logging.
87-
LogHTTPBody bool
78+
LogHTTPBody *bool
8879

8980
// An integer value representing the logging level. The default log level
9081
// is zero (0), which represents no logging. Set to a non-zero value to
9182
// perform logging.
92-
LogLevel uint
83+
LogLevel *int
9384

9485
// The logger writer interface to write logging messages to. Defaults to
9586
// standard out.
@@ -98,15 +89,15 @@ type Config struct {
9889
// The maximum number of times that a request will be retried for failures.
9990
// Defaults to -1, which defers the max retry setting to the service specific
10091
// configuration.
101-
MaxRetries int
92+
MaxRetries *int
10293

10394
// Disables semantic parameter validation, which validates input for missing
10495
// required fields and/or other semantic request input errors.
105-
DisableParamValidation bool
96+
DisableParamValidation *bool
10697

10798
// Disables the computation of request and response checksums, e.g.,
10899
// CRC32 checksums in Amazon DynamoDB.
109-
DisableComputeChecksums bool
100+
DisableComputeChecksums *bool
110101

111102
// Set this to `true` to force the request to use path-style addressing,
112103
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client will
@@ -116,111 +107,166 @@ type Config struct {
116107
// @note This configuration option is specific to the Amazon S3 service.
117108
// @see http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html
118109
// Amazon S3: Virtual Hosting of Buckets
119-
S3ForcePathStyle bool
110+
S3ForcePathStyle *bool
120111
}
121112

122-
// Copy will return a shallow copy of the Config object.
123-
func (c Config) Copy() Config {
124-
dst := Config{}
125-
dst.Credentials = c.Credentials
126-
dst.Endpoint = c.Endpoint
127-
dst.Region = c.Region
128-
dst.DisableSSL = c.DisableSSL
129-
dst.HTTPClient = c.HTTPClient
130-
dst.LogHTTPBody = c.LogHTTPBody
131-
dst.LogLevel = c.LogLevel
132-
dst.Logger = c.Logger
133-
dst.MaxRetries = c.MaxRetries
134-
dst.DisableParamValidation = c.DisableParamValidation
135-
dst.DisableComputeChecksums = c.DisableComputeChecksums
136-
dst.S3ForcePathStyle = c.S3ForcePathStyle
137-
138-
return dst
139-
}
140-
141-
// Merge merges the newcfg attribute values into this Config. Each attribute
142-
// will be merged into this config if the newcfg attribute's value is non-zero.
143-
// Due to this, newcfg attributes with zero values cannot be merged in. For
144-
// example bool attributes cannot be cleared using Merge, and must be explicitly
145-
// set on the Config structure.
146-
func (c Config) Merge(newcfg *Config) *Config {
147-
if newcfg == nil {
113+
// NewConfig returns a new Config pointer that can be chained with builder methods to
114+
// set multiple configuration values inline without using pointers.
115+
//
116+
// svc := s3.New(aws.NewConfig().WithRegion("us-west-2").WithMaxRetries(10))
117+
//
118+
func NewConfig() *Config {
119+
return &Config{}
120+
}
121+
122+
// WithCredentials sets a config Credentials value returning a Config pointer
123+
// for chaining.
124+
func (c *Config) WithCredentials(creds *credentials.Credentials) *Config {
125+
c.Credentials = creds
126+
return c
127+
}
128+
129+
// WithEndpoint sets a config Endpoint value returning a Config pointer for
130+
// chaining.
131+
func (c *Config) WithEndpoint(endpoint string) *Config {
132+
c.Endpoint = &endpoint
133+
return c
134+
}
135+
136+
// WithRegion sets a config Region value returning a Config pointer for
137+
// chaining.
138+
func (c *Config) WithRegion(region string) *Config {
139+
c.Region = &region
140+
return c
141+
}
142+
143+
// WithDisableSSL sets a config DisableSSL value returning a Config pointer
144+
// for chaining.
145+
func (c *Config) WithDisableSSL(disable bool) *Config {
146+
c.DisableSSL = &disable
147+
return c
148+
}
149+
150+
// WithHTTPClient sets a config HTTPClient value returning a Config pointer
151+
// for chaining.
152+
func (c *Config) WithHTTPClient(client *http.Client) *Config {
153+
c.HTTPClient = client
154+
return c
155+
}
156+
157+
// WithMaxRetries sets a config MaxRetries value returning a Config pointer
158+
// for chaining.
159+
func (c *Config) WithMaxRetries(max int) *Config {
160+
c.MaxRetries = &max
161+
return c
162+
}
163+
164+
// WithDisableParamValidation sets a config DisableParamValidation value
165+
// returning a Config pointer for chaining.
166+
func (c *Config) WithDisableParamValidation(disable bool) *Config {
167+
c.DisableParamValidation = &disable
168+
return c
169+
}
170+
171+
// WithDisableComputeChecksums sets a config DisableComputeChecksums value
172+
// returning a Config pointer for chaining.
173+
func (c *Config) WithDisableComputeChecksums(disable bool) *Config {
174+
c.DisableComputeChecksums = &disable
175+
return c
176+
}
177+
178+
// WithLogHTTPBody sets a config LogHTTPBody value returning a Config pointer
179+
// for chaining.
180+
func (c *Config) WithLogHTTPBody(logHTTPBody bool) *Config {
181+
c.LogHTTPBody = &logHTTPBody
182+
return c
183+
}
184+
185+
// WithLogLevel sets a config LogLevel value returning a Config pointer for
186+
// chaining.
187+
func (c *Config) WithLogLevel(level int) *Config {
188+
c.LogLevel = &level
189+
return c
190+
}
191+
192+
// WithLogger sets a config Logger value returning a Config pointer for
193+
// chaining.
194+
func (c *Config) WithLogger(logger io.Writer) *Config {
195+
c.Logger = logger
196+
return c
197+
}
198+
199+
// WithS3ForcePathStyle sets a config S3ForcePathStyle value returning a Config
200+
// pointer for chaining.
201+
func (c *Config) WithS3ForcePathStyle(force bool) *Config {
202+
c.S3ForcePathStyle = &force
203+
return c
204+
}
205+
206+
// Merge returns a new Config with the other Config's attribute values merged into
207+
// this Config. If the other Config's attribute is nil it will not be merged into
208+
// the new Config to be returned.
209+
func (c Config) Merge(other *Config) *Config {
210+
if other == nil {
148211
return &c
149212
}
150213

151-
cfg := Config{}
214+
dst := c
152215

153-
if newcfg.Credentials != nil {
154-
cfg.Credentials = newcfg.Credentials
155-
} else {
156-
cfg.Credentials = c.Credentials
216+
if other.Credentials != nil {
217+
dst.Credentials = other.Credentials
157218
}
158219

159-
if newcfg.Endpoint != "" {
160-
cfg.Endpoint = newcfg.Endpoint
161-
} else {
162-
cfg.Endpoint = c.Endpoint
220+
if other.Endpoint != nil {
221+
dst.Endpoint = other.Endpoint
163222
}
164223

165-
if newcfg.Region != "" {
166-
cfg.Region = newcfg.Region
167-
} else {
168-
cfg.Region = c.Region
224+
if other.Region != nil {
225+
dst.Region = other.Region
169226
}
170227

171-
if newcfg.DisableSSL {
172-
cfg.DisableSSL = newcfg.DisableSSL
173-
} else {
174-
cfg.DisableSSL = c.DisableSSL
228+
if other.DisableSSL != nil {
229+
dst.DisableSSL = other.DisableSSL
175230
}
176231

177-
if newcfg.HTTPClient != nil {
178-
cfg.HTTPClient = newcfg.HTTPClient
179-
} else {
180-
cfg.HTTPClient = c.HTTPClient
232+
233+
if other.HTTPClient != nil {
234+
dst.HTTPClient = other.HTTPClient
181235
}
182236

183-
if newcfg.LogHTTPBody {
184-
cfg.LogHTTPBody = newcfg.LogHTTPBody
185-
} else {
186-
cfg.LogHTTPBody = c.LogHTTPBody
237+
if other.LogHTTPBody != nil {
238+
dst.LogHTTPBody = other.LogHTTPBody
187239
}
188240

189-
if newcfg.LogLevel != 0 {
190-
cfg.LogLevel = newcfg.LogLevel
191-
} else {
192-
cfg.LogLevel = c.LogLevel
241+
if other.LogLevel != nil {
242+
dst.LogLevel = other.LogLevel
193243
}
194244

195-
if newcfg.Logger != nil {
196-
cfg.Logger = newcfg.Logger
197-
} else {
198-
cfg.Logger = c.Logger
245+
if other.Logger != nil {
246+
dst.Logger = other.Logger
199247
}
200248

201-
if newcfg.MaxRetries != DefaultRetries {
202-
cfg.MaxRetries = newcfg.MaxRetries
203-
} else {
204-
cfg.MaxRetries = c.MaxRetries
249+
if other.MaxRetries != nil {
250+
dst.MaxRetries = other.MaxRetries
205251
}
206252

207-
if newcfg.DisableParamValidation {
208-
cfg.DisableParamValidation = newcfg.DisableParamValidation
209-
} else {
210-
cfg.DisableParamValidation = c.DisableParamValidation
253+
if other.DisableParamValidation != nil {
254+
dst.DisableParamValidation = other.DisableParamValidation
211255
}
212256

213-
if newcfg.DisableComputeChecksums {
214-
cfg.DisableComputeChecksums = newcfg.DisableComputeChecksums
215-
} else {
216-
cfg.DisableComputeChecksums = c.DisableComputeChecksums
257+
if other.DisableComputeChecksums != nil {
258+
dst.DisableComputeChecksums = other.DisableComputeChecksums
217259
}
218260

219-
if newcfg.S3ForcePathStyle {
220-
cfg.S3ForcePathStyle = newcfg.S3ForcePathStyle
221-
} else {
222-
cfg.S3ForcePathStyle = c.S3ForcePathStyle
261+
if other.S3ForcePathStyle != nil {
262+
dst.S3ForcePathStyle = other.S3ForcePathStyle
223263
}
224264

225-
return &cfg
265+
return &dst
266+
}
267+
268+
// Copy will return a shallow copy of the Config object.
269+
func (c Config) Copy() *Config {
270+
dst := c
271+
return &dst
226272
}

0 commit comments

Comments
 (0)