forked from ebhomengo/niki
feat: add product list api
This commit is contained in:
parent
0948b36012
commit
c01d3678ae
|
|
@ -1,6 +1,23 @@
|
|||
package errmsg
|
||||
|
||||
type ErrorResponse struct {
|
||||
Message string `json:"message"` // General error message
|
||||
Errors map[string]interface{} `json:"errors,omitempty"` // Additional detail of error
|
||||
InternalErrCode string `json:"internal_error_code,omitempty"` // Custom error code (optional)
|
||||
}
|
||||
|
||||
func (e ErrorResponse) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
const (
|
||||
ErrValidationFailed = "input validation failed"
|
||||
ErrUnexpectedError = "unexpected error occurred"
|
||||
ErrInvalidRequestFormat = "invalid request format"
|
||||
ErrGetUserInfo = "get user info failed"
|
||||
ErrFailedDecodeBase64 = "decode data to base 64 failed"
|
||||
ErrFailedUnmarshalJson = "unmarshal data to JSON failed"
|
||||
ErrUnauthorized = "unauthorized"
|
||||
ErrorMsgAdminNotAllowed = "admin is not allowed"
|
||||
ErrorMsgNotFound = "record not found"
|
||||
ErrorMsgSomethingWentWrong = "something went wrong"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package productapp
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.gocasts.ir/ebhomengo/niki/productapp/service/product"
|
||||
"log"
|
||||
|
||||
httpserver "git.gocasts.ir/ebhomengo/niki/delivery/http_server"
|
||||
|
|
@ -25,6 +26,7 @@ type Config struct {
|
|||
type Application struct {
|
||||
Config Config
|
||||
HTTPServer *producthttp.Server
|
||||
productSvc product.Service
|
||||
DB *productdb.DB
|
||||
Echo *echo.Echo
|
||||
}
|
||||
|
|
@ -40,11 +42,14 @@ func Setup(cfg Config) *Application {
|
|||
Router: e,
|
||||
}
|
||||
|
||||
srv := producthttp.NewServer(hsrv)
|
||||
productSvc := product.New(productDB)
|
||||
|
||||
srv := producthttp.NewServer(hsrv, productSvc)
|
||||
srv.RegisterRoutes()
|
||||
|
||||
return &Application{
|
||||
Config: cfg,
|
||||
productSvc: productSvc,
|
||||
HTTPServer: srv,
|
||||
DB: productDB,
|
||||
Echo: e,
|
||||
|
|
|
|||
|
|
@ -1,17 +1,38 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||
"git.gocasts.ir/ebhomengo/niki/productapp/service/product"
|
||||
"github.com/labstack/echo/v4"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Handler struct{}
|
||||
|
||||
func NewHandler() *Handler {
|
||||
return &Handler{}
|
||||
type Handler struct {
|
||||
productService product.Service
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func (h Handler) HealthCheck(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
|
||||
func NewHandler(productService product.Service) *Handler {
|
||||
return &Handler{
|
||||
productService: productService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h Handler) getProductList(c echo.Context) error {
|
||||
var req product.GetProductListRequest
|
||||
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, errmsg.ErrorResponse{
|
||||
Message: errmsg.ErrInvalidRequestFormat,
|
||||
})
|
||||
}
|
||||
|
||||
response, err := h.productService.GetProducts(c.Request().Context(), req)
|
||||
if err != nil {
|
||||
// todo handle validation error
|
||||
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
func (h Handler) HealthCheck(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, map[string]string{"status": "healthy"})
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
package http
|
||||
|
|
@ -1,16 +1,19 @@
|
|||
package http
|
||||
|
||||
import httpserver "git.gocasts.ir/ebhomengo/niki/delivery/http_server"
|
||||
import (
|
||||
httpserver "git.gocasts.ir/ebhomengo/niki/delivery/http_server"
|
||||
"git.gocasts.ir/ebhomengo/niki/productapp/service/product"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
HTTPServer *httpserver.Server
|
||||
Handler *Handler
|
||||
}
|
||||
|
||||
func NewServer(httpserver *httpserver.Server) *Server {
|
||||
func NewServer(httpserver *httpserver.Server, productSvc product.Service) *Server {
|
||||
return &Server{
|
||||
HTTPServer: httpserver,
|
||||
Handler: NewHandler(),
|
||||
Handler: NewHandler(productSvc),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -22,5 +25,10 @@ func (s *Server) Stop() {}
|
|||
|
||||
func (s *Server) RegisterRoutes() {
|
||||
r := s.HTTPServer.Router
|
||||
r.GET("health-check", s.Handler.HealthCheck)
|
||||
r.GET("health-check/1", s.Handler.HealthCheck)
|
||||
|
||||
productGroup := r.Group("/v1/products")
|
||||
|
||||
productGroup.GET("", s.Handler.getProductList)
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
package database
|
||||
|
||||
import "git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||
import (
|
||||
"context"
|
||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||
"git.gocasts.ir/ebhomengo/niki/productapp/service/product"
|
||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
conn *mysql.DB
|
||||
|
|
@ -11,3 +16,42 @@ func New(conn *mysql.DB) *DB {
|
|||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
func (db *DB) GetProducts(ctx context.Context, page, pageSize uint) ([]product.Product, error) {
|
||||
const Op = "domain.repository.mysql.order.get-shipping"
|
||||
|
||||
query := "SELECT * FROM products ORDER BY id DESC limit ? offset ?"
|
||||
rows, err := db.conn.Conn().Query(query, page, pageSize)
|
||||
|
||||
if rows.Err() != nil {
|
||||
return []product.Product{}, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
var products []product.Product
|
||||
|
||||
for rows.Next() {
|
||||
var s product.Product
|
||||
|
||||
err := rows.Scan(
|
||||
&s.ID,
|
||||
&s.Name,
|
||||
&s.Slug,
|
||||
&s.Description,
|
||||
&s.Price,
|
||||
&s.Stock,
|
||||
&s.IsActive,
|
||||
&s.Features,
|
||||
&s.CreatedAt,
|
||||
&s.DeletedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, richerror.New(Op).WithErr(err)
|
||||
}
|
||||
|
||||
products = append(products, s)
|
||||
}
|
||||
|
||||
return products, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ import (
|
|||
)
|
||||
|
||||
type Product struct {
|
||||
ID uint
|
||||
Name string
|
||||
Slug string
|
||||
Description string
|
||||
Price float64
|
||||
Stock int
|
||||
IsActive bool
|
||||
Features string
|
||||
CreatedAt time.Time
|
||||
DeletedAt sql.NullTime
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
Description string `json:"description"`
|
||||
Price float64 `json:"price"`
|
||||
Stock int `json:"stock"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Features string `json:"features"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
DeletedAt sql.NullTime `json:"-"`
|
||||
}
|
||||
|
||||
type ProductImage struct {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
package product
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrFailedGetProductList = errors.New("failed to get products list")
|
||||
ErrFailedCreateProduct = errors.New("failed to create product")
|
||||
ErrFailedFindProduct = errors.New("failed to find product")
|
||||
ErrCantAccessToUpdateProduct = errors.New("you are not allowed to edit this product")
|
||||
ErrFailedUpdateProduct = errors.New("failed to update product")
|
||||
ErrFailedToPreparedStatement = errors.New("failed to prepared statement: %v")
|
||||
ErrCantAccess = errors.New("you are not allowed to this action")
|
||||
)
|
||||
|
|
@ -1 +1,12 @@
|
|||
package product
|
||||
|
||||
import "git.gocasts.ir/ebhomengo/niki/param"
|
||||
|
||||
type GetProductListRequest struct {
|
||||
param.PaginationRequest
|
||||
}
|
||||
|
||||
type GetProductListResponse struct {
|
||||
Data []Product `json:"data"`
|
||||
param.PaginationResponse
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1,38 @@
|
|||
package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
GetProducts(ctx context.Context, page, pageSize uint) ([]Product, error)
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
repository Repository
|
||||
}
|
||||
|
||||
func New(repo Repository) Service {
|
||||
return Service{
|
||||
repository: repo,
|
||||
}
|
||||
}
|
||||
|
||||
func (s Service) GetProducts(ctx context.Context, req GetProductListRequest) (GetProductListResponse, error) {
|
||||
|
||||
page := req.GetPageNumber()
|
||||
pageSize := req.PageSize
|
||||
|
||||
products, err := s.repository.GetProducts(ctx, page, pageSize)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return GetProductListResponse{}, errmsg.ErrorResponse{
|
||||
Message: ErrFailedGetProductList.Error(),
|
||||
Errors: map[string]interface{}{"repository_error": err.Error()},
|
||||
}
|
||||
}
|
||||
|
||||
return GetProductListResponse{Data: products}, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue