leankg 0.16.7

Lightweight Knowledge Graph for AI-Assisted Development
Documentation
package api

import (
	"encoding/json"
	"net/http"
	"strconv"
	"time"

	"go-api-service/internal/middleware"
	"go-api-service/internal/services"
	"go-api-service/pkg/logger"
)

type Handler struct {
	userService  *services.UserService
	orderService *services.OrderService
	logger       logger.Logger
}

func NewHandler(userSvc *services.UserService, orderSvc *services.OrderService, log logger.Logger) *Handler {
	return &Handler{
		userService:  userSvc,
		orderService: orderSvc,
		logger:       log,
	}
}

func SetupRouter(h *Handler, cfg interface{}) *http.ServeMux {
	mux := http.NewServeMux()
	
	h.registerRoutes(mux)
	
	return mux
}

func (h *Handler) registerRoutes(mux *http.ServeMux) {
	mux.HandleFunc("GET /health", h.healthCheck)
	mux.HandleFunc("GET /api/v1/users", h.listUsers)
	mux.HandleFunc("GET /api/v1/users/{id}", h.getUser)
	mux.HandleFunc("POST /api/v1/users", h.createUser)
	mux.HandleFunc("PUT /api/v1/users/{id}", h.updateUser)
	mux.HandleFunc("DELETE /api/v1/users/{id}", h.deleteUser)
	mux.HandleFunc("GET /api/v1/orders", h.listOrders)
	mux.HandleFunc("GET /api/v1/orders/{id}", h.getOrder)
	mux.HandleFunc("POST /api/v1/orders", h.createOrder)
}

func (h *Handler) healthCheck(w http.ResponseWriter, r *http.Request) {
	response := map[string]interface{}{
		"status":    "healthy",
		"timestamp": time.Now().UTC(),
		"service":   "go-api-service",
	}
	
	h.writeJSON(w, http.StatusOK, response)
}

func (h *Handler) listUsers(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	limit := h.parseIntParam(r.URL.Query().Get("limit"), 50)
	offset := h.parseIntParam(r.URL.Query().Get("offset"), 0)
	
	users, err := h.userService.ListUsers(ctx, limit, offset)
	if err != nil {
		h.handleError(w, r, err)
		return
	}
	
	h.writeJSON(w, http.StatusOK, map[string]interface{}{
		"data":   users,
		"limit":  limit,
		"offset": offset,
	})
}

func (h *Handler) getUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	id := h.getPathParam(r.URL.Path, "id")
	if id == "" {
		h.writeError(w, http.StatusBadRequest, "missing user id")
		return
	}
	
	user, err := h.userService.GetUser(ctx, id)
	if err != nil {
		h.handleError(w, r, err)
		return
	}
	
	h.writeJSON(w, http.StatusOK, user)
}

func (h *Handler) createUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	var input struct {
		Name     string `json:"name"`
		Email    string `json:"email"`
		Password string `json:"password"`
	}
	
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		h.writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}
	
	user, err := h.userService.CreateUser(ctx, input.Name, input.Email, input.Password)
	if err != nil {
		h.handleError(w, r, err)
		return
	}
	
	h.writeJSON(w, http.StatusCreated, user)
}

func (h *Handler) updateUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	id := h.getPathParam(r.URL.Path, "id")
	if id == "" {
		h.writeError(w, http.StatusBadRequest, "missing user id")
		return
	}
	
	var input struct {
		Name  string `json:"name"`
		Email string `json:"email"`
	}
	
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		h.writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}
	
	user, err := h.userService.UpdateUser(ctx, id, input.Name, input.Email)
	if err != nil {
		h.handleError(w, r, err)
		return
	}
	
	h.writeJSON(w, http.StatusOK, user)
}

func (h *Handler) deleteUser(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	id := h.getPathParam(r.URL.Path, "id")
	if id == "" {
		h.writeError(w, http.StatusBadRequest, "missing user id")
		return
	}
	
	if err := h.userService.DeleteUser(ctx, id); err != nil {
		h.handleError(w, r, err)
		return
	}
	
	h.writeJSON(w, http.StatusNoContent, nil)
}

func (h *Handler) listOrders(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	userID := r.URL.Query().Get("user_id")
	limit := h.parseIntParam(r.URL.Query().Get("limit"), 50)
	offset := h.parseIntParam(r.URL.Query().Get("offset"), 0)
	
	orders, err := h.orderService.ListOrders(ctx, userID, limit, offset)
	if err != nil {
		h.handleError(w, r, err)
		return
	}
	
	h.writeJSON(w, http.StatusOK, map[string]interface{}{
		"data":   orders,
		"limit":  limit,
		"offset": offset,
	})
}

func (h *Handler) getOrder(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	id := h.getPathParam(r.URL.Path, "id")
	if id == "" {
		h.writeError(w, http.StatusBadRequest, "missing order id")
		return
	}
	
	order, err := h.orderService.GetOrder(ctx, id)
	if err != nil {
		h.handleError(w, r, err)
		return
	}
	
	h.writeJSON(w, http.StatusOK, order)
}

func (h *Handler) createOrder(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	var input struct {
		UserID    string  `json:"user_id"`
		Product   string  `json:"product"`
		Quantity  int     `json:"quantity"`
		TotalPrice float64 `json:"total_price"`
	}
	
	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
		h.writeError(w, http.StatusBadRequest, "invalid request body")
		return
	}
	
	order, err := h.orderService.CreateOrder(ctx, input.UserID, input.Product, input.Quantity, input.TotalPrice)
	if err != nil {
		h.handleError(w, r, err)
		return
	}
	
	h.writeJSON(w, http.StatusCreated, order)
}

func (h *Handler) parseIntParam(value string, defaultValue int) int {
	if value == "" {
		return defaultValue
	}
	i, err := strconv.Atoi(value)
	if err != nil {
		return defaultValue
	}
	return i
}

func (h *Handler) getPathParam(path, key string) string {
	return ""
}

func (h *Handler) writeJSON(w http.ResponseWriter, status int, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(data)
}

func (h *Handler) writeError(w http.ResponseWriter, status int, message string) {
	h.writeJSON(w, status, map[string]string{"error": message})
}

func (h *Handler) handleError(w http.ResponseWriter, r *http.Request, err error) {
	h.logger.Error("Request error: " + err.Error())
	
	status := http.StatusInternalServerError
	if err == middleware.ErrUnauthorized {
		status = http.StatusUnauthorized
	} else if err == middleware.ErrForbidden {
		status = http.StatusForbidden
	}
	
	h.writeError(w, status, err.Error())
}