dukcapil/internal/handler/dukcapil_handler.go
Aditya Siregar bc64eb20ea add dukcapil
2026-05-07 04:01:32 +07:00

76 lines
2.5 KiB
Go

package handler
import (
"net/http"
"strings"
"go-backend-template/internal/constants"
"go-backend-template/internal/contract"
"go-backend-template/internal/logger"
"go-backend-template/internal/util"
"github.com/gin-gonic/gin"
)
type DukcapilHandler struct {
dukcapilService DukcapilService
}
func NewDukcapilHandler(dukcapilService DukcapilService) *DukcapilHandler {
return &DukcapilHandler{dukcapilService: dukcapilService}
}
// FaceMatch handles POST /api/v1/dukcapil/face-match (1:N face recognition).
func (h *DukcapilHandler) FaceMatch(c *gin.Context) {
var req contract.FaceMatchRequest
if err := c.ShouldBindJSON(&req); err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("DukcapilHandler::FaceMatch -> request binding failed")
h.sendValidationError(c, "Invalid request body", constants.MalformedFieldErrorCode)
return
}
if strings.TrimSpace(req.TransactionID) == "" {
h.sendValidationError(c, "transaction_id is required", constants.MissingFieldErrorCode)
return
}
if strings.TrimSpace(req.TransactionSource) == "" {
h.sendValidationError(c, "transaction_source is required", constants.MissingFieldErrorCode)
return
}
if strings.TrimSpace(req.Threshold) == "" {
h.sendValidationError(c, "threshold is required", constants.MissingFieldErrorCode)
return
}
if strings.TrimSpace(req.Image) == "" {
h.sendValidationError(c, "image is required (base64-encoded)", constants.MissingFieldErrorCode)
return
}
res, err := h.dukcapilService.FaceMatch(c.Request.Context(), &req)
if err != nil {
logger.FromContext(c.Request.Context()).WithError(err).Error("DukcapilHandler::FaceMatch -> upstream call failed")
c.JSON(http.StatusBadGateway, &contract.ErrorResponse{
Error: "upstream_error",
Message: err.Error(),
Code: http.StatusBadGateway,
Details: map[string]interface{}{"entity": constants.DukcapilHandlerEntity},
})
return
}
logger.FromContext(c.Request.Context()).Infof("DukcapilHandler::FaceMatch -> tid=%s errorCode=%s matches=%d", res.TID, res.ErrorCode, len(res.Matches))
util.HandleResponse(c.Writer, c.Request, contract.BuildSuccessResponse(res), "DukcapilHandler::FaceMatch")
}
func (h *DukcapilHandler) sendValidationError(c *gin.Context, message, code string) {
c.JSON(http.StatusBadRequest, &contract.ErrorResponse{
Error: "validation_error",
Message: message,
Code: http.StatusBadRequest,
Details: map[string]interface{}{
"error_code": code,
"entity": constants.DukcapilHandlerEntity,
},
})
}