├── .gitignore ├── go.mod ├── internal ├── handlers │ ├── health.go │ ├── payment.go │ └── account.go ├── services │ ├── health-service.go │ ├── payment-service.go │ ├── account-service.go │ └── account-service_test.go ├── domain │ ├── account.go │ ├── payment.go │ ├── health.go │ ├── health_test.go │ └── account_test.go └── repositories │ ├── memory-db.go │ ├── memory-db_test.go │ └── sqlite-db.go ├── go.sum ├── cmd ├── cli │ └── main.go └── httpserver │ └── main.go └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | /**/*.db 3 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module hexagonal-example 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/google/uuid v1.3.0 7 | github.com/gorilla/mux v1.8.0 8 | github.com/mattn/go-sqlite3 v1.14.9 9 | ) 10 | -------------------------------------------------------------------------------- /internal/handlers/health.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "encoding/json" 5 | "hexagonal-example/internal/services" 6 | "net/http" 7 | ) 8 | 9 | type HTTPHealthHandler struct { 10 | HealthService services.InterfaceHealth 11 | } 12 | 13 | func (h HTTPHealthHandler) HealthCheck(w http.ResponseWriter, r *http.Request) { 14 | w.Header().Set("Content-Type", "application/json") 15 | status := h.HealthService.IsAppHealthy() 16 | 17 | json.NewEncoder(w).Encode(status) 18 | } 19 | -------------------------------------------------------------------------------- /internal/services/health-service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "hexagonal-example/internal/domain" 5 | ) 6 | 7 | type InterfaceHealth interface { 8 | IsAppHealthy() bool 9 | } 10 | 11 | type service struct { 12 | Health domain.Health 13 | } 14 | 15 | func NewHealth(h domain.Health) *service { 16 | return &service{ 17 | Health: h, 18 | } 19 | } 20 | 21 | func (healthSrv service) IsAppHealthy() bool { 22 | status := healthSrv.Health.CheckHealth() 23 | return status 24 | } 25 | -------------------------------------------------------------------------------- /internal/domain/account.go: -------------------------------------------------------------------------------- 1 | package domain 2 | 3 | import ( 4 | "errors" 5 | "github.com/google/uuid" 6 | ) 7 | 8 | type Account struct { 9 | Id uuid.UUID 10 | Money float64 11 | } 12 | 13 | func (acc Account) Balance() (balance float64) { 14 | return acc.Money 15 | } 16 | 17 | func (acc *Account) Withdraw(amount float64) error { 18 | if (acc.Money - amount) < 0 { 19 | return errors.New("no enough funds") 20 | } 21 | 22 | acc.Money = acc.Balance() - amount 23 | 24 | return nil 25 | } 26 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 2 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 3 | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= 4 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 5 | github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= 6 | github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 7 | -------------------------------------------------------------------------------- /internal/domain/payment.go: -------------------------------------------------------------------------------- 1 | package domain 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/google/uuid" 7 | ) 8 | 9 | type Payment struct { 10 | Id uuid.UUID 11 | FromAccount uuid.UUID 12 | ToAccount uuid.UUID 13 | Money float64 14 | } 15 | 16 | func (p *Payment) Pay() error { 17 | if p.Money <= 10 { 18 | return errors.New( 19 | "poor clients are not accepted, find something more expensive to buy", 20 | ) 21 | } 22 | fmt.Println(p.Id) 23 | fmt.Println(p.FromAccount) 24 | fmt.Println(p.ToAccount) 25 | fmt.Println(p.Money) 26 | 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /internal/domain/health.go: -------------------------------------------------------------------------------- 1 | package domain 2 | 3 | import ( 4 | "log" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | type Health struct{} 10 | 11 | func (h Health) CheckHealth() bool { 12 | // check request time 13 | requestTime, err := calculateRequestToExternalService() 14 | if err != nil { 15 | log.Println(err) 16 | } 17 | if requestTime >= 5000 { 18 | return false 19 | } 20 | return true 21 | } 22 | 23 | func calculateRequestToExternalService() (int, error) { 24 | min := 1000 25 | max := 10000 26 | rand.Seed(time.Now().UnixNano()) 27 | result := rand.Intn(max-min) + min 28 | return result, nil 29 | } 30 | -------------------------------------------------------------------------------- /internal/domain/health_test.go: -------------------------------------------------------------------------------- 1 | package domain 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func TestCalculateRequestToExternalService(t *testing.T) { 9 | got, err := calculateRequestToExternalService() 10 | if err != nil { 11 | t.Error(err) 12 | } 13 | 14 | minWanted := 1000 15 | maxWanted := 10000 16 | 17 | if got < minWanted || got > maxWanted { 18 | t.Errorf("wanted external service to respond between %d and %d, got: %d", minWanted, maxWanted, got) 19 | } 20 | } 21 | 22 | func TestHealthCheckHealth(t *testing.T) { 23 | 24 | h := Health{} 25 | status := h.CheckHealth() 26 | 27 | wanted := "bool" 28 | got := reflect.TypeOf(status).String() 29 | 30 | if got != wanted { 31 | t.Errorf("wanted: %s, got: %s", wanted, got) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /cmd/cli/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | _ "github.com/mattn/go-sqlite3" 6 | "hexagonal-example/internal/domain" 7 | "hexagonal-example/internal/repositories" 8 | "hexagonal-example/internal/services" 9 | "log" 10 | ) 11 | 12 | func main() { 13 | //dbRepository := repositories.NewMemoryDb() 14 | dbRepository := repositories.NewSqliteDB() 15 | 16 | acc := domain.Account{ 17 | Money: 100, 18 | } 19 | 20 | srv := services.NewAccountService(dbRepository) 21 | id, err := srv.Create(acc) 22 | if err != nil { 23 | log.Println(err) 24 | } 25 | err = srv.WithdrawFromAccount(id, 50) 26 | if err != nil { 27 | log.Println(err) 28 | return 29 | } 30 | 31 | balance, err := srv.Balance(id) 32 | if err != nil { 33 | log.Println(err) 34 | return 35 | } 36 | 37 | fmt.Println(balance) 38 | 39 | } 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hexagonal architecture bank account example 2 | 3 | Esse repositório contém um pouco dos meus estudos sobre arquitetura hexagonal. 4 | 5 | Go Lang é a linguagem utilizada. 6 | 7 | ## Estrutura 8 | 9 | ``` 10 | ├── cmd 11 | │   ├── cli 12 | │   │   └── main.go 13 | │   └── httpserver 14 | │   └── main.go 15 | ├── go.mod 16 | ├── go.sum 17 | ├── internal 18 | │   ├── domain 19 | │   │   ├── account.go 20 | │   │   ├── account_test.go 21 | │   │   ├── health.go 22 | │   │   └── payment.go 23 | │   ├── handlers 24 | │   │   ├── account.go 25 | │   │   ├── health.go 26 | │   │   └── payment.go 27 | │   ├── repositories 28 | │   │   ├── memory-db.go 29 | │   │   └── memory-db_test.go 30 | │   └── services 31 | │   ├── account-service.go 32 | │   ├── account-service_test.go 33 | │   ├── health-service.go 34 | │   └── payment-service.go 35 | ``` 36 | -------------------------------------------------------------------------------- /internal/handlers/payment.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "github.com/google/uuid" 5 | "hexagonal-example/internal/domain" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | type PaymentInterface interface { 11 | DoPayment(payment domain.Payment) (bool, error) 12 | } 13 | 14 | type HTTPPaymentHandler struct { 15 | paymentService PaymentInterface 16 | } 17 | 18 | func NewHTTPPaymentHandler(paymentService PaymentInterface) *HTTPPaymentHandler { 19 | return &HTTPPaymentHandler{ 20 | paymentService: paymentService, 21 | } 22 | } 23 | 24 | func (srv HTTPPaymentHandler) RegisterPayment(w http.ResponseWriter, r *http.Request) { 25 | payment := domain.Payment{ 26 | Id: uuid.New(), 27 | Money: 100, 28 | } 29 | status, err := srv.paymentService.DoPayment(payment) 30 | if err != nil { 31 | log.Println(err) 32 | w.Write([]byte("payment error")) 33 | return 34 | } 35 | log.Printf("payment succeed, status: %T", status) 36 | w.Write([]byte("payment")) 37 | } 38 | -------------------------------------------------------------------------------- /internal/domain/account_test.go: -------------------------------------------------------------------------------- 1 | package domain 2 | 3 | import ( 4 | "github.com/google/uuid" 5 | "testing" 6 | ) 7 | 8 | func TestAccountBalance(t *testing.T) { 9 | 10 | acc := Account{ 11 | Id: uuid.New(), 12 | Money: 100, 13 | } 14 | 15 | balance := acc.Balance() 16 | 17 | if acc.Money != balance { 18 | t.Errorf("wanted: %T, got: %T", acc.Money, balance) 19 | } 20 | } 21 | 22 | func TestAccountWithdrawSuccess(t *testing.T) { 23 | 24 | wanted := 0 25 | 26 | acc := Account{ 27 | Id: uuid.New(), 28 | Money: 100, 29 | } 30 | 31 | err := acc.Withdraw(100) 32 | if err != nil { 33 | t.Error(err) 34 | } 35 | 36 | if acc.Money != 0 { 37 | t.Errorf("wanted: %T, got: %T", wanted, acc.Money) 38 | } 39 | } 40 | 41 | func TestAccountWithdrawNoFunds(t *testing.T) { 42 | 43 | acc := Account{ 44 | Id: uuid.New(), 45 | Money: 100, 46 | } 47 | 48 | err := acc.Withdraw(200) 49 | if err.Error() != "no enough funds" { 50 | t.Error(err) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /internal/repositories/memory-db.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "errors" 5 | "github.com/google/uuid" 6 | "hexagonal-example/internal/domain" 7 | ) 8 | 9 | type memoryDb struct { 10 | instance map[uuid.UUID]interface{} 11 | } 12 | 13 | func NewMemoryDb() *memoryDb { 14 | memDb := make(map[uuid.UUID]interface{}) 15 | return &memoryDb{ 16 | instance: memDb, 17 | } 18 | } 19 | 20 | func (memDb *memoryDb) GetAccount(accountId uuid.UUID) (*domain.Account, error) { 21 | 22 | account := memDb.instance[accountId] 23 | acc := domain.Account{ 24 | Id: uuid.New(), 25 | Money: 100, 26 | } 27 | 28 | if account == nil { 29 | return nil, errors.New("account doesnt exist") 30 | } 31 | 32 | //return account, nil 33 | return &acc, nil 34 | } 35 | 36 | func (memDb *memoryDb) SaveAccount(account *domain.Account) error { 37 | memDb.instance[uuid.New()] = account 38 | return nil 39 | } 40 | 41 | func (memDb *memoryDb) SavePayment(payment domain.Payment) error { 42 | memDb.instance[uuid.New()] = payment 43 | 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /internal/repositories/memory-db_test.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "hexagonal-example/internal/domain" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestNewMemoryDb(t *testing.T) { 10 | 11 | memDb := NewMemoryDb() 12 | 13 | mockedMemDb := make(map[int]*domain.Account) 14 | 15 | if !reflect.DeepEqual(memDb.account, mockedMemDb) { 16 | t.Errorf("wanted: %v, got: %v", memDb.account, mockedMemDb) 17 | } 18 | } 19 | 20 | func TestMemoryDbGetAccountDoesntExist(t *testing.T) { 21 | memDb := NewMemoryDb() 22 | _, err := memDb.Get(0) 23 | if err.Error() != "account doesnt exist" { 24 | t.Error(err) 25 | } 26 | } 27 | 28 | func TestMemoryDbGetAccountExists(t *testing.T) { 29 | memDb := NewMemoryDb() 30 | 31 | wanted := domain.Account{ 32 | Id: 1, 33 | Money: 100, 34 | } 35 | 36 | err := memDb.Save(&wanted) 37 | if err != nil { 38 | t.Error(err) 39 | } 40 | 41 | got, err := memDb.Get(1) 42 | if err != nil { 43 | t.Error(err) 44 | } 45 | 46 | if got.Id != wanted.Id { 47 | t.Errorf("wanted: %d, got: %d", wanted.Id, got.Id) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /internal/services/payment-service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "hexagonal-example/internal/domain" 5 | "log" 6 | ) 7 | 8 | type PaymentInterface interface { 9 | SavePayment(payment domain.Payment) error 10 | } 11 | 12 | type PaymentService struct { 13 | PaymentRepository PaymentInterface 14 | } 15 | 16 | func NewPayment(paymentRepository PaymentInterface) *PaymentService { 17 | return &PaymentService{ 18 | PaymentRepository: paymentRepository, 19 | } 20 | } 21 | 22 | func (srv PaymentService) DoPayment(payment domain.Payment) (bool, error) { 23 | err := payment.Pay() 24 | if err != nil { 25 | log.Println(err) 26 | return false, err 27 | } 28 | 29 | err = validatePayment(payment) 30 | if err != nil { 31 | log.Println(err) 32 | return false, err 33 | } 34 | 35 | err = srv.PaymentRepository.SavePayment(payment) 36 | if err != nil { 37 | log.Println(err) 38 | return false, err 39 | } 40 | 41 | return true, nil 42 | } 43 | 44 | func validatePayment(payment domain.Payment) error { 45 | // check if payment is legit 46 | log.Printf("validating payment id: %s\n", payment.Id) 47 | log.Println("valid!") 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /cmd/httpserver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gorilla/mux" 5 | "hexagonal-example/internal/domain" 6 | "hexagonal-example/internal/handlers" 7 | "hexagonal-example/internal/repositories" 8 | "hexagonal-example/internal/services" 9 | "log" 10 | "net/http" 11 | ) 12 | 13 | func main() { 14 | 15 | // database instance 16 | //dbRepository := repositories.NewMemoryDb() 17 | dbRepository := repositories.NewSqliteDB() 18 | // instantiate database service 19 | accService := services.NewAccountService(dbRepository) 20 | 21 | // bank http handler 22 | accountHandler := handlers.NewHTTPHandler(accService) 23 | 24 | // health service 25 | healthService := services.NewHealth(domain.Health{}) 26 | // health http handler 27 | healthHandler := handlers.HTTPHealthHandler{ 28 | HealthService: healthService, 29 | } 30 | 31 | payService := services.NewPayment(dbRepository) 32 | paymentHandler := handlers.NewHTTPPaymentHandler(payService) 33 | 34 | r := mux.NewRouter() 35 | r.HandleFunc("/account/create", accountHandler.Create).Methods(http.MethodPost) 36 | r.HandleFunc("/account/balance/{id}", accountHandler.Balance).Methods(http.MethodGet) 37 | r.HandleFunc("/payment", paymentHandler.RegisterPayment).Methods(http.MethodPost) 38 | r.HandleFunc("/health", healthHandler.HealthCheck).Methods(http.MethodGet) 39 | log.Println("listening at port 7000...") 40 | panic(http.ListenAndServe(":7000", r)) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /internal/services/account-service.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "github.com/google/uuid" 5 | "hexagonal-example/internal/domain" 6 | "log" 7 | ) 8 | 9 | type AccountRepositoryInterface interface { 10 | GetAccount(accountId uuid.UUID) (*domain.Account, error) 11 | SaveAccount(account *domain.Account) error 12 | } 13 | 14 | type accountService struct { 15 | accountRepository AccountRepositoryInterface 16 | } 17 | 18 | func NewAccountService(databaseRepository AccountRepositoryInterface) *accountService { 19 | return &accountService{ 20 | accountRepository: databaseRepository, 21 | } 22 | } 23 | 24 | func (srv accountService) WithdrawFromAccount(id uuid.UUID, amount float64) error { 25 | account, err := srv.accountRepository.GetAccount(id) 26 | if err != nil { 27 | return err 28 | } 29 | 30 | err = account.Withdraw(amount) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | return nil 36 | } 37 | 38 | func (srv accountService) Balance(id uuid.UUID) (float64, error) { 39 | account, err := srv.accountRepository.GetAccount(id) 40 | if err != nil { 41 | log.Println(err) 42 | return 0, err 43 | } 44 | return account.Balance(), nil 45 | } 46 | 47 | func (srv accountService) Create(account domain.Account) (uuid.UUID, error) { 48 | account.Id = uuid.New() 49 | err := srv.accountRepository.SaveAccount(&account) 50 | if err != nil { 51 | log.Println(err) 52 | return uuid.Nil, err 53 | } 54 | return account.Id, nil 55 | } 56 | -------------------------------------------------------------------------------- /internal/repositories/sqlite-db.go: -------------------------------------------------------------------------------- 1 | package repositories 2 | 3 | import ( 4 | "database/sql" 5 | "github.com/google/uuid" 6 | _ "github.com/mattn/go-sqlite3" 7 | "hexagonal-example/internal/domain" 8 | "log" 9 | ) 10 | 11 | type sqliteDB struct { 12 | sqlite *sql.DB 13 | } 14 | 15 | func NewSqliteDB() *sqliteDB { 16 | db, err := sql.Open("sqlite3", "../../internal/repositories/local.db") 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | // todo: add migration 22 | _, err = db.Exec(` 23 | DROP TABLE IF EXISTS account; 24 | CREATE TABLE account ( 25 | id TEXT, 26 | money INT 27 | ); 28 | `) 29 | 30 | return &sqliteDB{ 31 | sqlite: db, 32 | } 33 | } 34 | 35 | func (db sqliteDB) GetAccount(accountId uuid.UUID) (*domain.Account, error) { 36 | stmt := ` 37 | SELECT id, money 38 | FROM account 39 | WHERE id = $1; 40 | ` 41 | rows := db.sqlite.QueryRow(stmt, accountId) 42 | 43 | var account domain.Account 44 | err := rows.Scan(&account.Id, &account.Money) 45 | if err != nil { 46 | log.Println(err) 47 | return nil, err 48 | } 49 | 50 | return &account, nil 51 | } 52 | 53 | func (db sqliteDB) SaveAccount(account *domain.Account) error { 54 | stmt := ` 55 | INSERT INTO account (id, money) 56 | VALUES ($1, $2); 57 | ` 58 | _, err := db.sqlite.Exec(stmt, account.Id, account.Money) 59 | if err != nil { 60 | log.Println(err) 61 | return err 62 | } 63 | 64 | return nil 65 | } 66 | 67 | func (db sqliteDB) SavePayment(payment domain.Payment) error { 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /internal/services/account-service_test.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "github.com/google/uuid" 5 | "hexagonal-example/internal/domain" 6 | "hexagonal-example/internal/repositories" 7 | "reflect" 8 | "testing" 9 | ) 10 | 11 | func TestNew(t *testing.T) { 12 | memDb := repositories.NewMemoryDb() 13 | srv := NewAccountService(memDb) 14 | 15 | srvInstance := &accountService{} 16 | 17 | if reflect.TypeOf(srv) != reflect.TypeOf(srvInstance) { 18 | t.Errorf("wanted: instance of *services, got: instance of %v", reflect.TypeOf(srvInstance)) 19 | } 20 | } 21 | 22 | func TestServiceWithdrawFromAccount(t *testing.T) { 23 | 24 | memDb := repositories.NewMemoryDb() 25 | srv := NewAccountService(memDb) 26 | 27 | id := uuid.New() 28 | acc := domain.Account{ 29 | Id: id, 30 | Money: 100, 31 | } 32 | 33 | err := srv.accountRepository.Save(&acc) 34 | if err != nil { 35 | t.Error(err) 36 | } 37 | 38 | err = srv.WithdrawFromAccount(id, 100) 39 | if err != nil { 40 | t.Error(err) 41 | } 42 | 43 | if acc.Balance() != 0 { 44 | t.Error("amount should be zero") 45 | } 46 | } 47 | 48 | func TestServiceBalance(t *testing.T) { 49 | 50 | memDb := repositories.NewMemoryDb() 51 | srv := NewAccountService(memDb) 52 | 53 | wanted := 100.1 54 | 55 | id := uuid.New() 56 | acc := domain.Account{ 57 | Id: id, 58 | Money: wanted, 59 | } 60 | 61 | err := srv.accountRepository.Save(&acc) 62 | if err != nil { 63 | t.Error(err) 64 | } 65 | 66 | balance, err := srv.Balance(id) 67 | if err != nil { 68 | t.Error(err) 69 | } 70 | 71 | if wanted != balance { 72 | t.Errorf("wanted: %T, got: %T", wanted, balance) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /internal/handlers/account.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/google/uuid" 7 | "github.com/gorilla/mux" 8 | "hexagonal-example/internal/domain" 9 | "io/ioutil" 10 | "log" 11 | "net/http" 12 | ) 13 | 14 | type AccountServiceInterface interface { 15 | Balance(id uuid.UUID) (float64, error) 16 | Create(domain.Account) (uuid.UUID, error) 17 | } 18 | 19 | type HTTPAccountHandler struct { 20 | accountService AccountServiceInterface 21 | } 22 | 23 | func NewHTTPHandler(accountService AccountServiceInterface) *HTTPAccountHandler { 24 | return &HTTPAccountHandler{ 25 | accountService: accountService, 26 | } 27 | } 28 | 29 | func (h HTTPAccountHandler) SendSMS(w http.ResponseWriter, r *http.Request) { 30 | fmt.Println("smsSent") 31 | w.Write([]byte("ok")) 32 | } 33 | 34 | func (h HTTPAccountHandler) Balance(w http.ResponseWriter, r *http.Request) { 35 | 36 | w.Header().Set("Content-Type", "application/json") 37 | 38 | pathVars := mux.Vars(r) 39 | id := pathVars["id"] 40 | accUuid := uuid.MustParse(id) 41 | balance, err := h.accountService.Balance(accUuid) 42 | if err != nil { 43 | log.Println(err) 44 | } 45 | 46 | jsonData := map[string]interface{}{ 47 | "id": accUuid, 48 | "balance": balance, 49 | } 50 | 51 | err = json.NewEncoder(w).Encode(jsonData) 52 | if err != nil { 53 | log.Println(err) 54 | } 55 | } 56 | 57 | func (h HTTPAccountHandler) Create(w http.ResponseWriter, r *http.Request) { 58 | 59 | w.Header().Set("Content-Type", "application/json") 60 | 61 | body, err := ioutil.ReadAll(r.Body) 62 | if err != nil { 63 | log.Println(err) 64 | } 65 | 66 | var acc domain.Account 67 | err = json.Unmarshal(body, &acc) 68 | if err != nil { 69 | log.Println(err) 70 | } 71 | 72 | newId, err := h.accountService.Create(acc) 73 | if err != nil { 74 | log.Println(err) 75 | } 76 | 77 | ret := map[string]string{ 78 | "id": newId.String(), 79 | } 80 | 81 | err = json.NewEncoder(w).Encode(ret) 82 | if err != nil { 83 | log.Println(err) 84 | } 85 | } 86 | --------------------------------------------------------------------------------