+5
.envrc
+5
.envrc
+1
-1
.gitignore
+1
-1
.gitignore
+47
README.org
+47
README.org
···
1
+
* Payment Gateway
2
+
3
+
4
+
** Getting started
5
+
6
+
*** Prerequisites
7
+
8
+
- [[https://hurl.dev][hurl]] :: CLI tool that runs http requests, similar to curl
9
+
- [[https://docs.docker.com/desktop/][docker]] :: Using docker to run project and mocks
10
+
- [[https://just.systems/][just]] :: CLI runner
11
+
- [[https://jqlang.org/][jq]] :: (Optional) CLI tool to query JSON data
12
+
13
+
If you're using nix, you can find a flake in the root of the project and run =nix develop= to download all the tools (or allow [[https://direnv.net/][direnv]] to auto import in your path)
14
+
15
+
*** Usage
16
+
17
+
Run docker compose to start mocks, the mocks will use ports =8002= and =8003= and the were created using [[https://github.com/mrak/stubby4node][stubby4node]]
18
+
19
+
#+begin_src shell
20
+
docker compose up
21
+
#+end_src
22
+
23
+
In another terminal, bulid and run the project with =just=, it will start the project in port =8000=
24
+
25
+
#+begin_src shell
26
+
just run
27
+
#+end_src
28
+
29
+
In other terminal, make the request with hurl
30
+
31
+
#+begin_src shell
32
+
hurl request.hurl
33
+
#+end_src
34
+
35
+
In case you want to see the response with json format, you can use jq
36
+
37
+
#+begin_src shell
38
+
hurl request.hurl | jq .
39
+
#+end_src
40
+
41
+
** Tests
42
+
43
+
To run all tests, you can run the command that it will run all tests from the project:
44
+
45
+
#+begin_src shell
46
+
just test
47
+
#+end_src
+5
-5
cmd/app/main.go
+5
-5
cmd/app/main.go
···
24
24
25
25
logger, _ := zap.NewDevelopment()
26
26
defer logger.Sync()
27
-
sugar := logger.Sugar()
28
27
29
28
providers := providers.NewUseProviders([]providers.Provider{
30
-
providers.NewBraintreeProvider(getEnv("BRAINTREE_URL", "http://localhost:8001")),
31
-
providers.NewStripeProvider(getEnv("STRIPE_URL", "http://localhost:8002")),
32
-
}, sugar)
29
+
providers.NewBraintreeProvider(getEnv("BRAINTREE_URL", "http://localhost:8001"), logger),
30
+
providers.NewStripeProvider(getEnv("STRIPE_URL", "http://localhost:8002"), logger),
31
+
}, logger)
33
32
paymentsService := service.NewPaymentService(providers)
34
33
35
34
port := getEnv("PORT", "8000")
36
-
server := web.NewServer(paymentsService, port, sugar)
35
+
server := web.NewServer(paymentsService, port, logger)
37
36
server.ConfigureRouter()
38
37
39
38
srvErr := make(chan error, 1)
40
39
go func() {
40
+
logger.Info("Starting server", zap.String("port", port))
41
41
srvErr <- server.Start(ctx)
42
42
}()
43
43
-17
docker-compose.yml
-17
docker-compose.yml
···
1
1
services:
2
-
api-gateway:
3
-
build:
4
-
dockerfile: $PWD/Dockerfile
5
-
ports:
6
-
- "8000:8000"
7
-
environment:
8
-
PORT: 8000
9
-
BRAINTREE_URL: stripe
10
-
STRIPE_URL: braintree
11
-
depends_on:
12
-
- stripe
13
-
- braintree
14
-
15
2
stripe:
16
3
build:
17
4
dockerfile: $PWD/Dockerfile-stubby
18
5
ports:
19
6
- "8002:8882"
20
-
environment:
21
-
PORT: 8882
22
7
volumes:
23
8
- $PWD/mocks/stripe.yml:/app/mock.yml
24
9
···
27
12
dockerfile: $PWD/Dockerfile-stubby
28
13
ports:
29
14
- "8001:8882"
30
-
environment:
31
-
PORT: 8882
32
15
volumes:
33
16
- $PWD/mocks/braintree.yml:/app/mock.yml
+61
flake.lock
+61
flake.lock
···
1
+
{
2
+
"nodes": {
3
+
"flake-utils": {
4
+
"inputs": {
5
+
"systems": "systems"
6
+
},
7
+
"locked": {
8
+
"lastModified": 1731533236,
9
+
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
10
+
"owner": "numtide",
11
+
"repo": "flake-utils",
12
+
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
13
+
"type": "github"
14
+
},
15
+
"original": {
16
+
"owner": "numtide",
17
+
"repo": "flake-utils",
18
+
"type": "github"
19
+
}
20
+
},
21
+
"nixpkgs": {
22
+
"locked": {
23
+
"lastModified": 1752012998,
24
+
"narHash": "sha256-Q82Ms+FQmgOBkdoSVm+FBpuFoeUAffNerR5yVV7SgT8=",
25
+
"owner": "NixOS",
26
+
"repo": "nixpkgs",
27
+
"rev": "2a2130494ad647f953593c4e84ea4df839fbd68c",
28
+
"type": "github"
29
+
},
30
+
"original": {
31
+
"owner": "NixOS",
32
+
"ref": "nixpkgs-unstable",
33
+
"repo": "nixpkgs",
34
+
"type": "github"
35
+
}
36
+
},
37
+
"root": {
38
+
"inputs": {
39
+
"flake-utils": "flake-utils",
40
+
"nixpkgs": "nixpkgs"
41
+
}
42
+
},
43
+
"systems": {
44
+
"locked": {
45
+
"lastModified": 1681028828,
46
+
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
47
+
"owner": "nix-systems",
48
+
"repo": "default",
49
+
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
50
+
"type": "github"
51
+
},
52
+
"original": {
53
+
"owner": "nix-systems",
54
+
"repo": "default",
55
+
"type": "github"
56
+
}
57
+
}
58
+
},
59
+
"root": "root",
60
+
"version": 7
61
+
}
+28
flake.nix
+28
flake.nix
···
1
+
{
2
+
description = "A Nix-flake-based Golang development environment";
3
+
4
+
inputs = {
5
+
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6
+
7
+
flake-utils.url = "github:numtide/flake-utils";
8
+
};
9
+
10
+
outputs = { self, nixpkgs, flake-utils }:
11
+
flake-utils.lib.eachDefaultSystem (system:
12
+
let
13
+
inherit (pkgs.lib) optional optionals;
14
+
15
+
pkgs = import nixpkgs { inherit system; };
16
+
in
17
+
{
18
+
devShells.default = pkgs.mkShell {
19
+
buildInputs = with pkgs; [
20
+
go
21
+
hurl
22
+
just
23
+
jq
24
+
];
25
+
};
26
+
}
27
+
);
28
+
}
+13
-1
internal/dto/payments.go
+13
-1
internal/dto/payments.go
···
1
1
package dto
2
2
3
+
import "github.com/google/uuid"
4
+
3
5
type PaymentCardInput struct {
4
6
Number string `json:"number"`
5
7
HolderName string `json:"holderName"`
···
17
19
}
18
20
19
21
type PaymentOutput struct {
20
-
Message string `json:"message"`
22
+
Id uuid.UUID `json:"id"`
23
+
CardId uuid.UUID `json:"cardId"`
24
+
CurrentAmount uint `json:"currentAmount"`
25
+
}
26
+
27
+
func NewPaymentOutput(id, cardId uuid.UUID, currentAmount uint) *PaymentOutput {
28
+
return &PaymentOutput{
29
+
Id: id,
30
+
CardId: cardId,
31
+
CurrentAmount: currentAmount,
32
+
}
21
33
}
+12
-3
internal/providers/braintree.go
+12
-3
internal/providers/braintree.go
···
8
8
9
9
"github.com/Tulkdan/payment-gateway/internal/domain"
10
10
"github.com/google/uuid"
11
+
"go.uber.org/zap"
11
12
)
12
13
13
14
type BraintreeProvider struct {
14
-
Url string
15
+
Url string
16
+
logger *zap.Logger
15
17
}
16
18
17
-
func NewBraintreeProvider(url string) *BraintreeProvider {
18
-
return &BraintreeProvider{Url: url}
19
+
func NewBraintreeProvider(url string, logger *zap.Logger) *BraintreeProvider {
20
+
return &BraintreeProvider{Url: url, logger: logger.Named("BraintreeProvider")}
19
21
}
20
22
21
23
type BraintreeChargeCard struct {
···
39
41
}
40
42
41
43
func (b *BraintreeProvider) Charge(ctx context.Context, request *domain.Payment) (*domain.Provider, error) {
44
+
url := b.Url + "/transactions"
45
+
46
+
b.logger.Debug("Making request to charge",
47
+
zap.String("url", url))
48
+
42
49
body := b.createChargeBody(request)
43
50
req, err := http.NewRequestWithContext(ctx, http.MethodPost, b.Url+"/charges", bytes.NewBuffer(body))
44
51
if err != nil {
···
52
59
if err != nil {
53
60
return nil, err
54
61
}
62
+
defer response.Body.Close()
63
+
55
64
return b.responseCharge(response)
56
65
}
57
66
+5
-1
internal/providers/braintree_test.go
+5
-1
internal/providers/braintree_test.go
···
12
12
"github.com/Tulkdan/payment-gateway/internal/domain"
13
13
"github.com/Tulkdan/payment-gateway/internal/providers"
14
14
"github.com/google/uuid"
15
+
"go.uber.org/zap"
15
16
)
16
17
17
18
func TestBraintree(t *testing.T) {
18
19
t.Run("should make request to url", func(t *testing.T) {
20
+
logger, _ := zap.NewDevelopment()
21
+
defer logger.Sync()
22
+
19
23
id, _ := uuid.Parse("2ee70bcb-5cb9-4412-a35f-c2a15fb88ef1")
20
24
cardId, _ := uuid.Parse("ed6ecd4c-81d5-4e63-bb12-99439ae559e7")
21
25
ctx := context.WithValue(t.Context(), "request-id", uuid.New().String())
···
56
60
CardId: cardId,
57
61
}
58
62
59
-
provider := providers.NewBraintreeProvider(server.URL)
63
+
provider := providers.NewBraintreeProvider(server.URL, logger)
60
64
response, err := provider.Charge(ctx, charge)
61
65
62
66
if err != nil {
+30
-16
internal/providers/provider.go
+30
-16
internal/providers/provider.go
···
9
9
"go.uber.org/zap"
10
10
)
11
11
12
-
var thirtySecondTimout = 30 * time.Second
12
+
var thirtySecondTimout = 5 * time.Second
13
13
14
14
type Provider interface {
15
15
GetName() string
···
19
19
type UseProviders struct {
20
20
providers []Provider
21
21
timeout time.Duration
22
-
logger *zap.SugaredLogger
22
+
logger *zap.Logger
23
23
}
24
24
25
-
func NewUseProviders(providers []Provider, logger *zap.SugaredLogger) *UseProviders {
25
+
func NewUseProviders(providers []Provider, logger *zap.Logger) *UseProviders {
26
26
return ConfigurableUseProvider(providers, logger, thirtySecondTimout)
27
27
}
28
28
29
-
func ConfigurableUseProvider(providers []Provider, logger *zap.SugaredLogger, timeout time.Duration) *UseProviders {
29
+
func ConfigurableUseProvider(providers []Provider, logger *zap.Logger, timeout time.Duration) *UseProviders {
30
30
return &UseProviders{
31
31
providers: providers,
32
-
logger: logger,
32
+
logger: logger.Named("UseProviders"),
33
33
timeout: timeout,
34
34
}
35
35
}
36
36
37
37
func (p *UseProviders) Payment(ctx context.Context, payment *domain.Payment) (*domain.Provider, error) {
38
38
var err error = nil
39
-
attempts := 0
40
39
41
40
for _, provider := range p.providers {
41
+
requestCtx, cancel := context.WithTimeout(ctx, p.timeout)
42
+
defer cancel()
43
+
44
+
dataCh, errCh := p.charge(requestCtx, payment, provider)
42
45
select {
43
-
case data := <-p.charge(ctx, payment, provider):
44
-
p.logger.Debugw("[Payment] Sending request successfully",
45
-
"provider", provider.GetName(),
46
-
"attempt", attempts)
46
+
case data := <-dataCh:
47
+
p.logger.Debug("[Payment] Received request successfully",
48
+
zap.String("provider", provider.GetName()))
47
49
48
50
return data, nil
51
+
case error := <-errCh:
52
+
p.logger.Error("[Payment] Received request with error",
53
+
zap.String("provider", provider.GetName()),
54
+
zap.String("error", error.Error()))
55
+
56
+
err = error
57
+
continue
49
58
case <-time.After(p.timeout):
50
-
p.logger.Errorw("[Payment] Timeout for provider to respond",
51
-
"provider", provider.GetName(),
52
-
"attempt", attempts)
59
+
p.logger.Error("[Payment] Timeout for provider to respond",
60
+
zap.String("provider", provider.GetName()))
61
+
62
+
cancel()
53
63
54
64
err = errors.New("Timeout")
55
65
continue
66
+
case <-ctx.Done():
67
+
cancel()
68
+
return nil, ctx.Err()
56
69
}
57
70
}
58
71
59
72
return nil, err
60
73
}
61
74
62
-
func (p *UseProviders) charge(ctx context.Context, charge *domain.Payment, provider Provider) chan *domain.Provider {
75
+
func (p *UseProviders) charge(ctx context.Context, charge *domain.Payment, provider Provider) (chan *domain.Provider, chan error) {
63
76
ch := make(chan *domain.Provider)
77
+
chError := make(chan error)
64
78
65
79
go func() {
66
80
response, err := provider.Charge(ctx, charge)
67
81
if err != nil {
68
-
close(ch)
82
+
chError <- err
69
83
return
70
84
}
71
85
ch <- response
72
86
}()
73
87
74
-
return ch
88
+
return ch, chError
75
89
}
+5
-8
internal/providers/provider_test.go
+5
-8
internal/providers/provider_test.go
···
31
31
t.Run("should make request for first provider", func(t *testing.T) {
32
32
logger, _ := zap.NewDevelopment()
33
33
defer logger.Sync()
34
-
sugar := logger.Sugar()
35
34
36
35
spyFirst := &SpyProvider{Timeout: 10 * time.Millisecond, Response: &domain.Provider{Description: "First"}}
37
36
spySecond := &SpyProvider{Timeout: 10 * time.Millisecond, Response: &domain.Provider{Description: "Second"}}
38
37
39
38
payment, _ := domain.NewPayment(1000, "R$", "", "card", domain.PaymentCard{Number: "", HolderName: "", CVV: "", ExpirationDate: "02/2025", Installments: 1})
40
39
41
-
useProvider := providers.ConfigurableUseProvider([]providers.Provider{spyFirst, spySecond}, sugar, 15*time.Millisecond)
40
+
useProvider := providers.ConfigurableUseProvider([]providers.Provider{spyFirst, spySecond}, logger, 15*time.Millisecond)
42
41
data, err := useProvider.Payment(context.Background(), payment)
43
42
44
43
if err != nil {
···
54
53
})
55
54
56
55
t.Run("should make request for second provider when first provider timeouts", func(t *testing.T) {
57
-
logger, _ := zap.NewProduction()
56
+
logger, _ := zap.NewDevelopment()
58
57
defer logger.Sync()
59
-
sugar := logger.Sugar()
60
58
61
59
spyFirst := &SpyProvider{Timeout: 20 * time.Millisecond, Response: &domain.Provider{Description: "First"}}
62
60
spySecond := &SpyProvider{Timeout: 10 * time.Millisecond, Response: &domain.Provider{Description: "Second"}}
63
61
64
62
payment, _ := domain.NewPayment(1000, "R$", "", "card", domain.PaymentCard{Number: "", HolderName: "", CVV: "", ExpirationDate: "02/2025", Installments: 1})
65
63
66
-
useProvider := providers.ConfigurableUseProvider([]providers.Provider{spyFirst, spySecond}, sugar, 15*time.Millisecond)
64
+
useProvider := providers.ConfigurableUseProvider([]providers.Provider{spyFirst, spySecond}, logger, 15*time.Millisecond)
67
65
data, err := useProvider.Payment(context.Background(), payment)
68
66
69
67
if err != nil {
···
79
77
})
80
78
81
79
t.Run("should return error when all providers timeout", func(t *testing.T) {
82
-
logger, _ := zap.NewProduction()
80
+
logger, _ := zap.NewDevelopment()
83
81
defer logger.Sync()
84
-
sugar := logger.Sugar()
85
82
86
83
spyFirst := &SpyProvider{Timeout: 20 * time.Millisecond, Response: &domain.Provider{Description: "First"}}
87
84
spySecond := &SpyProvider{Timeout: 20 * time.Millisecond, Response: &domain.Provider{Description: "Second"}}
88
85
89
86
payment, _ := domain.NewPayment(1000, "R$", "", "card", domain.PaymentCard{Number: "", HolderName: "", CVV: "", ExpirationDate: "02/2025", Installments: 1})
90
87
91
-
useProvider := providers.ConfigurableUseProvider([]providers.Provider{spyFirst, spySecond}, sugar, 5*time.Millisecond)
88
+
useProvider := providers.ConfigurableUseProvider([]providers.Provider{spyFirst, spySecond}, logger, 5*time.Millisecond)
92
89
data, err := useProvider.Payment(context.Background(), payment)
93
90
94
91
if data != nil {
+17
-9
internal/providers/stripe.go
+17
-9
internal/providers/stripe.go
···
8
8
9
9
"github.com/Tulkdan/payment-gateway/internal/domain"
10
10
"github.com/google/uuid"
11
+
"go.uber.org/zap"
11
12
)
12
13
13
14
type StripeProvider struct {
14
-
Url string
15
+
Url string
16
+
logger *zap.Logger
15
17
}
16
18
17
-
func NewStripeProvider(url string) *StripeProvider {
18
-
return &StripeProvider{Url: url}
19
+
func NewStripeProvider(url string, logger *zap.Logger) *StripeProvider {
20
+
return &StripeProvider{Url: url, logger: logger.Named("StripeProvider")}
19
21
}
20
22
21
23
type StripeChargeCard struct {
···
34
36
Card StripeChargeCard `json:"card"`
35
37
}
36
38
37
-
func (b *StripeProvider) Charge(ctx context.Context, request *domain.Payment) (*domain.Provider, error) {
38
-
body := b.createChargeBody(request)
39
-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, b.Url+"/transactions", bytes.NewBuffer(body))
39
+
func (s *StripeProvider) Charge(ctx context.Context, request *domain.Payment) (*domain.Provider, error) {
40
+
url := s.Url + "/transactions"
41
+
42
+
s.logger.Debug("Making request to charge",
43
+
zap.String("url", url))
44
+
45
+
body := s.createChargeBody(request)
46
+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewBuffer(body))
40
47
if err != nil {
41
48
return nil, err
42
49
}
···
48
55
if err != nil {
49
56
return nil, err
50
57
}
58
+
defer response.Body.Close()
51
59
52
-
return b.responseCharge(response)
60
+
return s.responseCharge(response)
53
61
}
54
62
55
-
func (b *StripeProvider) createChargeBody(request *domain.Payment) []byte {
63
+
func (s *StripeProvider) createChargeBody(request *domain.Payment) []byte {
56
64
toSend := &StripeCharge{
57
65
Amount: request.Amount,
58
66
Currency: request.Currency,
···
82
90
CardId uuid.UUID `json:"cardId"`
83
91
}
84
92
85
-
func (b *StripeProvider) responseCharge(response *http.Response) (*domain.Provider, error) {
93
+
func (s *StripeProvider) responseCharge(response *http.Response) (*domain.Provider, error) {
86
94
var data StripeChargeResponse
87
95
if err := json.NewDecoder(response.Body).Decode(&data); err != nil {
88
96
return nil, err
+5
-1
internal/providers/stripe_test.go
+5
-1
internal/providers/stripe_test.go
···
12
12
"github.com/Tulkdan/payment-gateway/internal/domain"
13
13
"github.com/Tulkdan/payment-gateway/internal/providers"
14
14
"github.com/google/uuid"
15
+
"go.uber.org/zap"
15
16
)
16
17
17
18
func TestStripe(t *testing.T) {
18
19
t.Run("should make request to url", func(t *testing.T) {
20
+
logger, _ := zap.NewDevelopment()
21
+
defer logger.Sync()
22
+
19
23
id, _ := uuid.Parse("2ee70bcb-5cb9-4412-a35f-c2a15fb88ef1")
20
24
cardId, _ := uuid.Parse("ed6ecd4c-81d5-4e63-bb12-99439ae559e7")
21
25
ctx := context.WithValue(t.Context(), "request-id", uuid.New().String())
···
56
60
CardId: cardId,
57
61
}
58
62
59
-
provider := providers.NewStripeProvider(server.URL)
63
+
provider := providers.NewStripeProvider(server.URL, logger)
60
64
response, err := provider.Charge(ctx, charge)
61
65
62
66
if err != nil {
+4
-4
internal/service/payment_service.go
+4
-4
internal/service/payment_service.go
···
2
2
3
3
import (
4
4
"context"
5
-
"fmt"
6
5
7
6
"github.com/Tulkdan/payment-gateway/internal/domain"
8
7
"github.com/Tulkdan/payment-gateway/internal/dto"
···
23
22
return nil, err
24
23
}
25
24
26
-
data, err := p.providers.Payment(ctx, payment)
25
+
providerData, err := p.providers.Payment(ctx, payment)
27
26
if err != nil {
27
+
payment.UpdateStatus(domain.StatusRejected)
28
28
return nil, err
29
29
}
30
30
31
-
fmt.Println(data)
31
+
payment.UpdateStatus(domain.StatusApproved)
32
32
33
-
return &dto.PaymentOutput{Message: "Processed successfully"}, nil
33
+
return dto.NewPaymentOutput(providerData.Id, providerData.CardId, providerData.CurrentAmount), nil
34
34
}
+12
-8
internal/web/handler/payments_handler.go
+12
-8
internal/web/handler/payments_handler.go
···
12
12
type PaymentsHandler struct {
13
13
paymentService *service.PaymentService
14
14
15
-
logger *zap.SugaredLogger
15
+
logger *zap.Logger
16
16
}
17
17
18
-
func NewPaymentsHandler(paymentsService *service.PaymentService, logger *zap.SugaredLogger) *PaymentsHandler {
18
+
func NewPaymentsHandler(paymentsService *service.PaymentService, logger *zap.Logger) *PaymentsHandler {
19
19
return &PaymentsHandler{
20
20
paymentService: paymentsService,
21
21
logger: logger.Named("PaymentHandler"),
···
25
25
func (p *PaymentsHandler) Create(w http.ResponseWriter, r *http.Request) {
26
26
var body dto.PaymentInput
27
27
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
28
-
p.logger.Errorw("Body incomplete",
29
-
"error", err.Error(),
30
-
"requestId", r.Context().Value("request-id").(string))
28
+
p.logger.Error("Body incomplete",
29
+
zap.String("error", err.Error()),
30
+
zap.String("requestId", r.Context().Value("request-id").(string)))
31
31
32
32
http.Error(w, err.Error(), http.StatusBadRequest)
33
33
return
···
35
35
36
36
response, err := p.paymentService.CreatePayment(r.Context(), body)
37
37
if err != nil {
38
-
p.logger.Errorw("Failed to create payment",
39
-
"error", err.Error(),
40
-
"requestId", r.Context().Value("request-id").(string))
38
+
p.logger.Error("Failed to create payment",
39
+
zap.String("error", err.Error()),
40
+
zap.String("requestId", r.Context().Value("request-id").(string)))
41
41
42
42
http.Error(w, err.Error(), http.StatusBadRequest)
43
43
return
44
44
}
45
+
46
+
p.logger.Debug("Processed request",
47
+
zap.Any("response", response),
48
+
zap.String("requestId", r.Context().Value("request-id").(string)))
45
49
46
50
w.Header().Set("Content-Type", "application/json")
47
51
w.WriteHeader(http.StatusOK)
+2
-2
internal/web/server.go
+2
-2
internal/web/server.go
···
16
16
port string
17
17
router *http.ServeMux
18
18
server *http.Server
19
-
logger *zap.SugaredLogger
19
+
logger *zap.Logger
20
20
21
21
paymentsService *service.PaymentService
22
22
}
23
23
24
-
func NewServer(paymentsService *service.PaymentService, port string, logger *zap.SugaredLogger) *Server {
24
+
func NewServer(paymentsService *service.PaymentService, port string, logger *zap.Logger) *Server {
25
25
return &Server{
26
26
port: port,
27
27
paymentsService: paymentsService,
+1
-1
mocks/braintree.yml
+1
-1
mocks/braintree.yml
+1
-1
mocks/stripe.yml
+1
-1
mocks/stripe.yml