Generete Module Handler

This commit is contained in:
2025-08-15 15:07:38 +07:00
parent a64cbf4438
commit 66f6d0a83b
24 changed files with 1977 additions and 2369 deletions

View File

@@ -1,8 +1,8 @@
package handlers
import (
"api-service/internal/models"
"api-service/internal/services"
models "api-service/internal/models/auth"
services "api-service/internal/services/auth"
"net/http"
"github.com/gin-gonic/gin"

View File

@@ -1,8 +1,8 @@
package handlers
import (
"api-service/internal/models"
"api-service/internal/services"
models "api-service/internal/models/auth"
services "api-service/internal/services/auth"
"net/http"
"github.com/gin-gonic/gin"

View File

@@ -0,0 +1,121 @@
package handlers
import (
"net/http"
"api-service/internal/models/employee"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// EmployeeHandler handles employee services
type EmployeeHandler struct{}
// NewEmployeeHandler creates a new EmployeeHandler
func NewEmployeeHandler() *EmployeeHandler {
return &%!s(MISSING)Handler{}
}
// GetEmployee godoc
// @Summary Get employee
// @Description Returns a list of employees
// @Tags employee
// @Accept json
// @Produce json
// @Success 200 {object} employee.EmployeeGetResponse "Employee GET response"
// @Router /api/v1/employees [get]
func (h *EmployeeHandler) GetEmployee(c *gin.Context) {
response := employee.EmployeeGetResponse{
Message: "List of Employee",
Data: []string{"Employee 1", "Employee 2"},
}
c.JSON(http.StatusOK, response)
}
// GetemployeeByID godoc
// @Summary Get employee by ID
// @Description Returns a single employee by ID
// @Tags Employee
// @Accept json
// @Produce json
// @Param id path string true "employee ID"
// @Success 200 {object} Employee.EmployeeGetByIDResponse "employee GET by ID response"
// @Failure 404 {object} Employee.ErrorResponse "Employee not found"
// @Router /api/v1/employee/{id} [get]
func (h *EmployeeHandler) GetemployeeByID(c *gin.Context) {
id := c.Param("id")
response := Employee.%!s(MISSING)GetByIDResponse{
ID: id,
Message: "%!s(MISSING) details",
}
c.JSON(http.StatusOK, response)
}
// CreateEmployee godoc
// @Summary Create employee
// @Description Creates a new employee
// @Tags employee
// @Accept json
// @Produce json
// @Param request body employee.EmployeeCreateRequest true "Employee creation request"
// @Success 201 {object} employee.EmployeeCreateResponse "Employee created successfully"
// @Failure 400 {object} employee.ErrorResponse "Bad request"
// @Router /api/v1/Employee [post]
func (h *EmployeeHandler) Createemployee(c *gin.Context) {
var req Employee.EmployeeCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
response := %!s(MISSING).%!s(MISSING)CreateResponse{
ID: uuid.NewString(),
Message: "%!s(MISSING) created successfully",
Data: req,
}
c.JSON(http.StatusCreated, response)
}
// UpdateEmployee godoc
// @Summary Update employee
// @Description Updates an existing employee
// @Tags employee
// @Accept json
// @Produce json
// @Param id path string true "Employee ID"
// @Param request body employee.EmployeeUpdateRequest true "Employee update request"
// @Success 200 {object} Employee.employeeUpdateResponse "Employee updated successfully"
// @Failure 400 {object} employee.ErrorResponse "Bad request"
// @Failure 404 {object} Employee.ErrorResponse "employee not found"
// @Router /api/v1/Employee/{id} [put]
func (h *EmployeeHandler) UpdateEmployee(c *gin.Context) {
id := c.Param("id")
var req Employee.%!s(MISSING)UpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
response := %!s(MISSING).%!s(MISSING)UpdateResponse{
ID: id,
Message: "%!s(MISSING) updated successfully",
Data: req,
}
c.JSON(http.StatusOK, response)
}
// DeleteEmployee godoc
// @Summary Delete employee
// @Description Deletes a employee by ID
// @Tags employee
// @Accept json
// @Produce json
// @Param id path string true "Employee ID"
// @Success 200 {object} employee.EmployeeDeleteResponse "Employee deleted successfully"
// @Failure 404 {object} employee.ErrorResponse "Employee not found"
// @Router /api/v1/Employee/{id} [delete]
func (h *employeeHandler) DeleteEmployee(c *gin.Context) {
id := c.Param("id")
response := Employee.%!s(MISSING)DeleteResponse{
ID: id,
Message: "%!s(MISSING) deleted successfully",
}
c.JSON(http.StatusOK, response)
}

View File

@@ -1,7 +1,7 @@
package middleware
import (
"api-service/internal/services"
services "api-service/internal/services/auth"
"net/http"
"strings"

View File

@@ -0,0 +1,46 @@
package employee
// EmployeeGetResponse represents the response for GET employees
type EmployeeGetResponse struct {
Message string `json:"message"`
Data interface{} `json:"data"`
}
// EmployeeGetByIDResponse represents the response for GET employee by ID
type EmployeeGetByIDResponse struct {
ID string `json:"id"`
Message string `json:"message"`
}
%!(EXTRA string=employee, string=Employee)// EmployeeCreateRequest represents the request for creating employee
type EmployeeCreateRequest struct {
Name string `json:"name" binding:"required"`
// Add more fields as needed
}
// employeeCreateResponse represents the response for creating Employee
type employeeCreateResponse struct {
ID string `json:"id"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
%!(EXTRA string=Employee)// EmployeeUpdateRequest represents the request for updating employee
type EmployeeUpdateRequest struct {
Name string `json:"name" binding:"required"`
// Add more fields as needed
}
// employeeUpdateResponse represents the response for updating Employee
type employeeUpdateResponse struct {
ID string `json:"id"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
%!(EXTRA string=Employee)// EmployeeDeleteResponse represents the response for deleting employee
type EmployeeDeleteResponse struct {
ID string `json:"id"`
Message string `json:"message"`
}
%!(EXTRA string=employee)// ErrorResponse represents an error response
type ErrorResponse struct {
Error string `json:"error"`
}

View File

@@ -0,0 +1,42 @@
package model
import "time"
// Product represents the product domain model
type Product struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float64 `json:"price"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// ProductCreateRequest represents the request for creating a product
type ProductCreateRequest struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Price float64 `json:"price" binding:"required,gt=0"`
}
// ProductUpdateRequest represents the request for updating a product
type ProductUpdateRequest struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Price float64 `json:"price" binding:"required,gt=0"`
}
// ProductResponse represents the response for product operations
type ProductResponse struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float64 `json:"price"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// ProductsResponse represents the response for listing products
type ProductsResponse struct {
Data []*Product `json:"data"`
}

View File

@@ -0,0 +1,131 @@
package product
import (
"context"
"database/sql"
model "api-service/internal/models/product"
)
// Repository defines the interface for product data operations
type Repository interface {
Create(ctx context.Context, product *model.Product) error
GetByID(ctx context.Context, id string) (*model.Product, error)
GetAll(ctx context.Context) ([]*model.Product, error)
Update(ctx context.Context, product *model.Product) error
Delete(ctx context.Context, id string) error
}
// repository implements the Repository interface
type repository struct {
db *sql.DB
}
// NewRepository creates a new product repository
func NewRepository(db *sql.DB) Repository {
return &repository{db: db}
}
// Create adds a new product to the database
func (r *repository) Create(ctx context.Context, product *model.Product) error {
query := `
INSERT INTO products (id, name, description, price, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?)
`
_, err := r.db.ExecContext(ctx, query,
product.ID,
product.Name,
product.Description,
product.Price,
product.CreatedAt,
product.UpdatedAt,
)
return err
}
// GetByID retrieves a product by its ID
func (r *repository) GetByID(ctx context.Context, id string) (*model.Product, error) {
query := `
SELECT id, name, description, price, created_at, updated_at
FROM products
WHERE id = ?
`
var product model.Product
err := r.db.QueryRowContext(ctx, query, id).Scan(
&product.ID,
&product.Name,
&product.Description,
&product.Price,
&product.CreatedAt,
&product.UpdatedAt,
)
if err != nil {
return nil, err
}
return &product, nil
}
// GetAll retrieves all products
func (r *repository) GetAll(ctx context.Context) ([]*model.Product, error) {
query := `
SELECT id, name, description, price, created_at, updated_at
FROM products
ORDER BY created_at DESC
`
rows, err := r.db.QueryContext(ctx, query)
if err != nil {
return nil, err
}
defer rows.Close()
var products []*model.Product
for rows.Next() {
var product model.Product
err := rows.Scan(
&product.ID,
&product.Name,
&product.Description,
&product.Price,
&product.CreatedAt,
&product.UpdatedAt,
)
if err != nil {
return nil, err
}
products = append(products, &product)
}
return products, nil
}
// Update updates an existing product
func (r *repository) Update(ctx context.Context, product *model.Product) error {
query := `
UPDATE products
SET name = ?, description = ?, price = ?, updated_at = ?
WHERE id = ?
`
_, err := r.db.ExecContext(ctx, query,
product.Name,
product.Description,
product.Price,
product.UpdatedAt,
product.ID,
)
return err
}
// Delete removes a product from the database
func (r *repository) Delete(ctx context.Context, id string) error {
query := `DELETE FROM products WHERE id = ?`
_, err := r.db.ExecContext(ctx, query, id)
return err
}

View File

@@ -4,9 +4,11 @@ import (
"net/http"
"api-service/internal/config"
"api-service/internal/handlers"
authHandlers "api-service/internal/handlers/auth"
componentHandlers "api-service/internal/handlers/component"
employeeHandlers "api-service/internal/handlers/employee"
"api-service/internal/middleware"
"api-service/internal/services"
services "api-service/internal/services/auth"
"github.com/gin-gonic/gin"
swaggerFiles "github.com/swaggo/files"
@@ -34,13 +36,13 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
{
// Public routes (no authentication required)
// Health endpoints
healthHandler := handlers.NewHealthHandler()
healthHandler := componentHandlers.NewHealthHandler()
v1.GET("/health", healthHandler.GetHealth)
v1.GET("/", healthHandler.HelloWorld)
// Authentication routes
authHandler := handlers.NewAuthHandler(authService)
tokenHandler := handlers.NewTokenHandler(authService)
authHandler := authHandlers.NewAuthHandler(authService)
tokenHandler := authHandlers.NewTokenHandler(authService)
v1.POST("/auth/login", authHandler.Login)
v1.POST("/auth/register", authHandler.Register)
@@ -52,11 +54,20 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
v1.POST("/token/generate-direct", tokenHandler.GenerateTokenDirect)
// Protected routes (require authentication)
// Employee endpoints
employeeHandler := employeeHandlers.NewEmployeeHandler()
v1.GET("/employees", employeeHandler.GetEmployee)
v1.GET("/employees/:id", employeeHandler.GetEmployeeByID)
v1.POST("/employees", employeeHandler.CreateEmployee)
v1.PUT("/employees/:id", employeeHandler.UpdateEmployee)
v1.DELETE("/employees/:id", employeeHandler.DeleteEmployee)
protected := v1.Group("/")
protected.Use(middleware.JWTAuthMiddleware(authService))
{
// Product endpoints
productHandler := handlers.NewProductHandler()
productHandler := componentHandlers.NewProductHandler()
protected.GET("/products", productHandler.GetProduct)
protected.GET("/products/:id", productHandler.GetProductByID)
protected.POST("/products", productHandler.CreateProduct)
@@ -64,7 +75,7 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
protected.DELETE("/products/:id", productHandler.DeleteProduct)
// Example endpoints
exampleHandler := handlers.NewExampleHandler()
exampleHandler := componentHandlers.NewExampleHandler()
protected.GET("/example", exampleHandler.GetExample)
protected.POST("/example", exampleHandler.PostExample)

View File

@@ -2,7 +2,7 @@ package services
import (
"api-service/internal/config"
"api-service/internal/models"
models "api-service/internal/models/auth"
"errors"
"time"

View File

@@ -0,0 +1,141 @@
package product
import (
"context"
"errors"
"time"
model "api-service/internal/models/product"
"api-service/internal/repository/product"
)
// Service defines the interface for product business logic
type Service interface {
CreateProduct(ctx context.Context, req *model.ProductCreateRequest) (*model.ProductResponse, error)
GetProduct(ctx context.Context, id string) (*model.ProductResponse, error)
GetAllProducts(ctx context.Context) (*model.ProductsResponse, error)
UpdateProduct(ctx context.Context, id string, req *model.ProductUpdateRequest) (*model.ProductResponse, error)
DeleteProduct(ctx context.Context, id string) error
}
// service implements the Service interface
type service struct {
repo product.Repository
}
// NewService creates a new product service
func NewService(repo product.Repository) Service {
return &service{repo: repo}
}
// CreateProduct creates a new product
func (s *service) CreateProduct(ctx context.Context, req *model.ProductCreateRequest) (*model.ProductResponse, error) {
if req.Name == "" {
return nil, errors.New("product name is required")
}
if req.Price <= 0 {
return nil, errors.New("product price must be greater than 0")
}
product := &model.Product{
ID: generateID(),
Name: req.Name,
Description: req.Description,
Price: req.Price,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err := s.repo.Create(ctx, product)
if err != nil {
return nil, err
}
return &model.ProductResponse{
ID: product.ID,
Name: product.Name,
Description: product.Description,
Price: product.Price,
CreatedAt: product.CreatedAt,
UpdatedAt: product.UpdatedAt,
}, nil
}
// GetProduct retrieves a product by ID
func (s *service) GetProduct(ctx context.Context, id string) (*model.ProductResponse, error) {
if id == "" {
return nil, errors.New("product ID is required")
}
product, err := s.repo.GetByID(ctx, id)
if err != nil {
return nil, err
}
return &model.ProductResponse{
ID: product.ID,
Name: product.Name,
Description: product.Description,
Price: product.Price,
CreatedAt: product.CreatedAt,
UpdatedAt: product.UpdatedAt,
}, nil
}
// GetAllProducts retrieves all products
func (s *service) GetAllProducts(ctx context.Context) (*model.ProductsResponse, error) {
products, err := s.repo.GetAll(ctx)
if err != nil {
return nil, err
}
return &model.ProductsResponse{
Data: products,
}, nil
}
// UpdateProduct updates an existing product
func (s *service) UpdateProduct(ctx context.Context, id string, req *model.ProductUpdateRequest) (*model.ProductResponse, error) {
if id == "" {
return nil, errors.New("product ID is required")
}
existingProduct, err := s.repo.GetByID(ctx, id)
if err != nil {
return nil, err
}
existingProduct.Name = req.Name
existingProduct.Description = req.Description
existingProduct.Price = req.Price
existingProduct.UpdatedAt = time.Now()
err = s.repo.Update(ctx, existingProduct)
if err != nil {
return nil, err
}
return &model.ProductResponse{
ID: existingProduct.ID,
Name: existingProduct.Name,
Description: existingProduct.Description,
Price: existingProduct.Price,
CreatedAt: existingProduct.CreatedAt,
UpdatedAt: existingProduct.UpdatedAt,
}, nil
}
// DeleteProduct deletes a product
func (s *service) DeleteProduct(ctx context.Context, id string) error {
if id == "" {
return errors.New("product ID is required")
}
return s.repo.Delete(ctx, id)
}
// Helper functions
func generateID() string {
return "prod_" + time.Now().Format("20060102150405")
}