Skip to content

Commit

Permalink
Merge pull request #215 from VictorAvelar/feature/idempotency-key-sup…
Browse files Browse the repository at this point in the history
…port
  • Loading branch information
VictorAvelar authored Jan 4, 2023
2 parents dbcb3af + 56c9ff5 commit 736483e
Show file tree
Hide file tree
Showing 20 changed files with 377 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
""
],
"formatting.gofumpt": true,
"ui.completion.usePlaceholders": true,
"ui.completion.usePlaceholders": false,
"ui.diagnostic.staticcheck": true,
"ui.semanticTokens": true
},
Expand Down
7 changes: 5 additions & 2 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tests:
- any: ["mollie/*_tests.go", "mollie/connect/*_tests.go"]
- any: ["mollie/*_test.go", "mollie/connect/*_test.go", "mollie/tools/*_test.go"]

documentation:
- docs/*
Expand All @@ -11,7 +11,7 @@ gh-actions:
- .github/**/*.yml

core:
- any: ["mollie/*.go", "!mollie/*_tests.go"]
- any: ["mollie/*.go", "!mollie/*_tests.go", "!mollie/tools/*"]

modules:
- go.*
Expand All @@ -24,3 +24,6 @@ config:

meta-files:
- any: ["Makefile", "README.md", "LICENSE", "SECURITY.md"]

tools:
- any: ["mollie/tools/*.go"]
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@ clean:
update-docs:
@godocdown ./mollie > docs/README.md
.PHONY: update-docs

sub-pkg-docs:
@godocdown ./mollie/connect > docs/connect/README.md
@godocdown ./mollie/tools > docs/tools/README.md
@godocdown ./mollie/tools/idempotency > docs/tools/idempotency/README.md
.PHONY: sub-pkg-docs
29 changes: 20 additions & 9 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ the name of the resource you want to interact with.

```go
const (
BaseURL string = "https://api.mollie.com/"
AuthHeader string = "Authorization"
TokenType string = "Bearer"
APITokenEnv string = "MOLLIE_API_TOKEN"
OrgTokenEnv string = "MOLLIE_ORG_TOKEN"
RequestContentType string = "application/json"
BaseURL string = "https://api.mollie.com/"
AuthHeader string = "Authorization"
TokenType string = "Bearer"
APITokenEnv string = "MOLLIE_API_TOKEN"
OrgTokenEnv string = "MOLLIE_ORG_TOKEN"
RequestContentType string = "application/json"
IdempotencyKeyHeader string = "Idempotency-Key"
)
```

Expand Down Expand Up @@ -471,6 +472,15 @@ NewAPIRequest is a wrapper around the http.NewRequest function.
It will setup the authentication headers/parameters according to the client
config.

#### func (*Client) SetIdempotencyKeyGenerator

```go
func (c *Client) SetIdempotencyKeyGenerator(kg idempotency.KeyGenerator)
```

SetIdempotencyKeyGenerator allows you to pass your own idempotency key
generator.

#### func (*Client) WithAuthenticationValue

```go
Expand Down Expand Up @@ -507,12 +517,13 @@ Config contains information that helps during the setup of a new Mollie client.
#### func NewConfig

```go
func NewConfig(t bool, auth string) *Config
func NewConfig(t, reqIdem bool, auth string) *Config
```

NewConfig builds a Mollie configuration object, it takes t to indicate if our
client is meant to create requests for testing and auth to indicate the
authentication method we want to use.
client is meant to create requests for testing, reqIdem to enable the request
idempotency beta feature, and auth to indicate the authentication method we want
to use.

#### type CreateShipmentRequest

Expand Down
14 changes: 14 additions & 0 deletions docs/connect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# connect

--
import "github.com/VictorAvelar/mollie-api-go/v3/mollie/connect"

## Usage

#### func OauthEndpoint

```go
func OauthEndpoint() *oauth2.Endpoint
```

OauthEndpoint is Mollies's OAuth 2.0 endpoint.
9 changes: 9 additions & 0 deletions docs/tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# tools

--
import "github.com/VictorAvelar/mollie-api-go/v3/mollie/tools"

package tools provides some common tools required by mollie's features in order
to maximize the library utility.

## Usage
61 changes: 61 additions & 0 deletions docs/tools/idempotency/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# idempotency

--
import "github.com/VictorAvelar/mollie-api-go/v3/mollie/tools/idempotency"

package idempotency contains the services in charge of generating a unique keys
to be passed in POST requests to ensure operation uniqueness.

See: <https://docs.mollie.com/overview/api-idempotency>

The std generator uses google's uuid library to return a new uuid as unique
idempotency key.

You can build your own generator and pass it to the library by implementing the
KeyGenerator interface.

## Usage

```go
const (
TestKeyExpected = "test_ikg_key"
)
```

#### type KeyGenerator

```go
type KeyGenerator interface {
// Generate encapsulates the logic to return a string representation of
// a unique idempotency key.
Generate() string
}
```

KeyGenerator describes the service in charge of generating a unique idempotency
key to be passed in POST requests to ensure operation uniqueness.

See: <https://docs.mollie.com/overview/api-idempotency>

#### func NewNopGenerator

```go
func NewNopGenerator(exp string) KeyGenerator
```

NewNopGenerator returns a dummy implementation of the IdempotencyKeyGenerator
interface.

Good for testing or when a predictable result is required.

If exp is an empty string, then TestKeyExpected is used as default value for the
NOpGenerator.

#### func NewStdGenerator

```go
func NewStdGenerator() KeyGenerator
```

NewStdGenerator returns an standard and common way of generating idempotency
unique keys.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/net v0.3.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand Down
15 changes: 9 additions & 6 deletions mollie/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ package mollie

// Config contains information that helps during the setup of a new Mollie client.
type Config struct {
testing bool
auth string
testing bool
auth string
reqIdempotency bool
}

// NewConfig builds a Mollie configuration object,
// it takes t to indicate if our client is meant to create requests for testing
// it takes t to indicate if our client is meant to create requests for testing,
// reqIdem to enable the request idempotency beta feature,
// and auth to indicate the authentication method we want to use.
func NewConfig(t bool, auth string) *Config {
func NewConfig(t, reqIdem bool, auth string) *Config {
return &Config{
testing: t,
auth: auth,
testing: t,
auth: auth,
reqIdempotency: reqIdem,
}
}
9 changes: 8 additions & 1 deletion mollie/config_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mollie

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -9,6 +10,7 @@ import (
func TestNewConfig(t *testing.T) {
type args struct {
t bool
ikg bool
auth string
}
tests := []struct {
Expand Down Expand Up @@ -63,8 +65,13 @@ func TestNewConfig(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := NewConfig(tt.args.t, tt.args.auth)
got := NewConfig(tt.args.t, tt.args.ikg, tt.args.auth)
assert.Equal(t, got, tt.want)
})
}
}

func ExampleNewConfig() {
fmt.Println(NewConfig(true, true, APITokenEnv))
// Output: &{true MOLLIE_API_TOKEN true}
}
37 changes: 28 additions & 9 deletions mollie/mollie.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ import (
"runtime"
"strings"

"github.com/VictorAvelar/mollie-api-go/v3/mollie/tools/idempotency"
"github.com/google/go-querystring/query"
)

// Constants holding values for client initialization and request instantiation.
const (
BaseURL string = "https://api.mollie.com/"
AuthHeader string = "Authorization"
TokenType string = "Bearer"
APITokenEnv string = "MOLLIE_API_TOKEN"
OrgTokenEnv string = "MOLLIE_ORG_TOKEN"
RequestContentType string = "application/json"
BaseURL string = "https://api.mollie.com/"
AuthHeader string = "Authorization"
TokenType string = "Bearer"
APITokenEnv string = "MOLLIE_API_TOKEN"
OrgTokenEnv string = "MOLLIE_ORG_TOKEN"
RequestContentType string = "application/json"
IdempotencyKeyHeader string = "Idempotency-Key"
)

var (
Expand All @@ -41,6 +43,8 @@ type Client struct {
client *http.Client
common service // Reuse a single struct instead of allocating one for each service on the heap.
config *Config
// Tools
idempotencyKeyProvider idempotency.KeyGenerator
// Services
Payments *PaymentsService
Chargebacks *ChargebacksService
Expand Down Expand Up @@ -148,6 +152,12 @@ func (c *Client) HasAccessToken() bool {
return accessTokenExpr.Match([]byte(c.authentication))
}

// SetIdempotencyKeyGenerator allows you to pass your own idempotency
// key generator.
func (c *Client) SetIdempotencyKeyGenerator(kg idempotency.KeyGenerator) {
c.idempotencyKeyProvider = kg
}

// NewAPIRequest is a wrapper around the http.NewRequest function.
//
// It will setup the authentication headers/parameters according to the client config.
Expand Down Expand Up @@ -193,6 +203,10 @@ func (c *Client) NewAPIRequest(ctx context.Context, method string, uri string, b
req.Header.Set("Accept", RequestContentType)
req.Header.Set("User-Agent", c.userAgent)

if c.config.reqIdempotency && c.idempotencyKeyProvider != nil && req.Method == http.MethodPost {
req.Header.Set(IdempotencyKeyHeader, c.idempotencyKeyProvider.Generate())
}

return
}

Expand Down Expand Up @@ -236,13 +250,18 @@ func NewClient(baseClient *http.Client, conf *Config) (mollie *Client, err error
uri, _ := url.Parse(BaseURL)

mollie = &Client{
BaseURL: uri,
client: baseClient,
config: conf,
BaseURL: uri,
client: baseClient,
config: conf,
idempotencyKeyProvider: nil,
}

mollie.common.client = mollie

if mollie.config.reqIdempotency {
mollie.common.client.idempotencyKeyProvider = idempotency.NewStdGenerator()
}

// services for resources
mollie.Payments = (*PaymentsService)(&mollie.common)
mollie.Chargebacks = (*ChargebacksService)(&mollie.common)
Expand Down
Loading

0 comments on commit 736483e

Please sign in to comment.