From cc26e98025ff63375e9926d32d9f9b17a9ab9017 Mon Sep 17 00:00:00 2001 From: Evgeniy Fedorov Date: Tue, 25 Jul 2023 18:26:53 +0300 Subject: [PATCH] Mock implementation of createOrder action (use-case). --- actions/actions.go | 5 +--- actions/createOrder.go | 38 ++++++++++++++++++++++++++++++ entity/order.go | 9 ++++---- go.mod | 5 ++++ go.sum | 4 ++++ main.go | 37 ++++++++++++++++++++++++++++++ repository/order.go | 30 ++++++++++++++++++++++-- rest/createOrder.go | 30 ++++++++++++++++++++++++ rest/responder.go | 52 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 200 insertions(+), 10 deletions(-) create mode 100644 actions/createOrder.go create mode 100644 go.sum create mode 100644 main.go create mode 100644 rest/createOrder.go create mode 100644 rest/responder.go diff --git a/actions/actions.go b/actions/actions.go index fa5af06..99a8915 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -2,10 +2,7 @@ package actions import "orders/entity" -type OrderCreator interface { - Create() *entity.Order -} - +// Action interfaces to be implemented. type ProductAdder interface { AddProduct(order *entity.Order, product *entity.Product) } diff --git a/actions/createOrder.go b/actions/createOrder.go new file mode 100644 index 0000000..01f983d --- /dev/null +++ b/actions/createOrder.go @@ -0,0 +1,38 @@ +package actions + +import ( + "github.com/google/uuid" + "orders/entity" + "orders/repository" + "time" +) + +// NewOrderRequest. +type NewOrderRequest struct{} + +// CreateOrder action. +type CreateOrder struct { + repo repository.OrderRepository +} + +// Constructor. +func NewCreateOrder(repo repository.OrderRepository) *CreateOrder { + return &CreateOrder{ + repo: repo, + } +} + +func (action *CreateOrder) Create(r NewOrderRequest) (*entity.Order, error) { + order := &entity.Order{ + Uuid: uuid.New().String(), + CreatedAt: time.Now(), + } + + err := action.repo.Save(order) + + if err != nil { + return nil, err + } + + return order, nil +} diff --git a/entity/order.go b/entity/order.go index 7f4ec2b..013037d 100644 --- a/entity/order.go +++ b/entity/order.go @@ -3,8 +3,9 @@ package entity import "time" type Order struct { - customerId string - products []Product - paymentId string - createdAt time.Time + Uuid string + CustomerId string + Products []Product + PaymentId string + CreatedAt time.Time } diff --git a/go.mod b/go.mod index fcdb39c..e8d9bb6 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,8 @@ module orders go 1.20 + +require ( + github.com/google/uuid v1.3.0 + github.com/gorilla/mux v1.8.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fee0108 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +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/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= diff --git a/main.go b/main.go new file mode 100644 index 0000000..1d4fca7 --- /dev/null +++ b/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "log" + "net/http" + "orders/actions" + "orders/repository" + "orders/rest" + "time" + + "github.com/gorilla/mux" +) + +func main() { + // Entity repository. + repo := repository.NewInMemoryOrderRepo() + + // Rest json responder. + respndr:=rest.NewResponder("2006-01-02 15:04:05") + + // New order controller. + cntrlr := rest.NewCreateOrder(actions.NewCreateOrder(repo), respndr) + + // Router and server. + r := mux.NewRouter() + r.HandleFunc("/create", cntrlr.Create) + + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8081", + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } + + log.Fatal(srv.ListenAndServe()) + +} diff --git a/repository/order.go b/repository/order.go index 619169c..a022549 100644 --- a/repository/order.go +++ b/repository/order.go @@ -3,7 +3,33 @@ package repository import "orders/entity" // Persists Order to db, filesystem, etc. -type orderRepository interface { - Save(order entity.Order) +type OrderRepository interface { + Save(order *entity.Order) error FindById(orderId string) *entity.Order } + +// InMemoryOrderRepo. +type InMemoryOrderRepo struct { + orders map[string]*entity.Order +} + +// Constructor. +func NewInMemoryOrderRepo() *InMemoryOrderRepo { + return &InMemoryOrderRepo{ + orders: make(map[string]*entity.Order), + } +} + +func (repo *InMemoryOrderRepo) Save(order *entity.Order) error { + repo.orders[order.Uuid] = order + return nil +} + +func (repo *InMemoryOrderRepo) FindById(orderId string) *entity.Order { + for _, order := range repo.orders { + if order.Uuid == orderId { + return order + } + } + return nil +} diff --git a/rest/createOrder.go b/rest/createOrder.go new file mode 100644 index 0000000..d2ec5fb --- /dev/null +++ b/rest/createOrder.go @@ -0,0 +1,30 @@ +package rest + +import ( + "net/http" + "orders/actions" +) + +// Create order controller. +type CreateOrder struct { + action *actions.CreateOrder + rspndr *Responder +} + +// Constructor. +func NewCreateOrder(action *actions.CreateOrder, rspndr *Responder) *CreateOrder { + return &CreateOrder{ + action: action, + rspndr: rspndr, + } +} + +func (c *CreateOrder) Create(w http.ResponseWriter, r *http.Request) { + order, err := c.action.Create(actions.NewOrderRequest{}) + + if err != nil { + c.rspndr.Error(w, http.StatusInternalServerError, err.Error()) + } + + c.rspndr.Success(w, order) +} diff --git a/rest/responder.go b/rest/responder.go new file mode 100644 index 0000000..65cce69 --- /dev/null +++ b/rest/responder.go @@ -0,0 +1,52 @@ +package rest + +import ( + "encoding/json" + "net/http" + "time" +) + +// JSON response object. +type Response struct { + Date string `json:"date"` + Message string `json:"message"` + Payload interface{} `json:"payload"` +} + +func NewResponse() *Response { + return &Response{} +} + +// Responder. +type Responder struct { + dateFormat string +} + +func NewResponder(dateFormat string) *Responder { + return &Responder{dateFormat: dateFormat} +} + +func (rspndr *Responder) Error(w http.ResponseWriter, statusCode int, message string) { + // Build json response. + r := NewResponse() + r.Date = time.Now().Format(rspndr.dateFormat) + r.Message = message + + // Send response. + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(statusCode) + json.NewEncoder(w).Encode(r) +} + +func (rspndr *Responder) Success(w http.ResponseWriter, payload interface{}) { + // Build json response. + r := NewResponse() + r.Date = time.Now().Format(rspndr.dateFormat) + r.Message = "ok" + r.Payload = payload + + // Send response. + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(r) +}