mirror of
https://github.com/EZ-Api/ez-api.git
synced 2026-01-13 17:47:51 +00:00
feat(api): add admin endpoints for binding management
Implement handlers for creating, listing, and updating model bindings. Register new routes in the admin server group and add DTO definitions. Update provider handlers to trigger binding synchronization on changes to ensure upstream mappings remain current.
This commit is contained in:
160
internal/api/binding_handler.go
Normal file
160
internal/api/binding_handler.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ez-api/ez-api/internal/dto"
|
||||
"github.com/ez-api/ez-api/internal/model"
|
||||
groupx "github.com/ez-api/foundation/group"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CreateBinding godoc
|
||||
// @Summary Create a new binding
|
||||
// @Description Create a new (namespace, public_model) binding to a route group and selector
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security AdminAuth
|
||||
// @Param binding body dto.BindingDTO true "Binding Info"
|
||||
// @Success 201 {object} model.Binding
|
||||
// @Failure 400 {object} gin.H
|
||||
// @Failure 500 {object} gin.H
|
||||
// @Router /admin/bindings [post]
|
||||
func (h *Handler) CreateBinding(c *gin.Context) {
|
||||
var req dto.BindingDTO
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
ns := strings.TrimSpace(req.Namespace)
|
||||
pm := strings.TrimSpace(req.PublicModel)
|
||||
if ns == "" || pm == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "namespace and public_model required"})
|
||||
return
|
||||
}
|
||||
|
||||
rg := groupx.Normalize(req.RouteGroup)
|
||||
if strings.TrimSpace(rg) == "" {
|
||||
rg = "default"
|
||||
}
|
||||
|
||||
st := strings.TrimSpace(req.Status)
|
||||
if st == "" {
|
||||
st = "active"
|
||||
}
|
||||
|
||||
selectorType := strings.TrimSpace(req.SelectorType)
|
||||
if selectorType == "" {
|
||||
selectorType = "exact"
|
||||
}
|
||||
|
||||
b := model.Binding{
|
||||
Namespace: ns,
|
||||
PublicModel: pm,
|
||||
RouteGroup: rg,
|
||||
SelectorType: selectorType,
|
||||
SelectorValue: strings.TrimSpace(req.SelectorValue),
|
||||
Status: st,
|
||||
}
|
||||
|
||||
if err := h.db.Create(&b).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create binding", "details": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.sync.SyncBindings(h.db); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sync bindings", "details": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, b)
|
||||
}
|
||||
|
||||
// ListBindings godoc
|
||||
// @Summary List bindings
|
||||
// @Description List all configured bindings
|
||||
// @Tags admin
|
||||
// @Produce json
|
||||
// @Security AdminAuth
|
||||
// @Success 200 {array} model.Binding
|
||||
// @Failure 500 {object} gin.H
|
||||
// @Router /admin/bindings [get]
|
||||
func (h *Handler) ListBindings(c *gin.Context) {
|
||||
var out []model.Binding
|
||||
if err := h.db.Find(&out).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to list bindings", "details": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, out)
|
||||
}
|
||||
|
||||
// UpdateBinding godoc
|
||||
// @Summary Update a binding
|
||||
// @Description Update an existing binding
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security AdminAuth
|
||||
// @Param id path int true "Binding ID"
|
||||
// @Param binding body dto.BindingDTO true "Binding Info"
|
||||
// @Success 200 {object} model.Binding
|
||||
// @Failure 400 {object} gin.H
|
||||
// @Failure 404 {object} gin.H
|
||||
// @Failure 500 {object} gin.H
|
||||
// @Router /admin/bindings/{id} [put]
|
||||
func (h *Handler) UpdateBinding(c *gin.Context) {
|
||||
idParam := c.Param("id")
|
||||
id, err := strconv.Atoi(idParam)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid id"})
|
||||
return
|
||||
}
|
||||
|
||||
var existing model.Binding
|
||||
if err := h.db.First(&existing, id).Error; err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "binding not found"})
|
||||
return
|
||||
}
|
||||
|
||||
var req dto.BindingDTO
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if ns := strings.TrimSpace(req.Namespace); ns != "" {
|
||||
existing.Namespace = ns
|
||||
}
|
||||
if pm := strings.TrimSpace(req.PublicModel); pm != "" {
|
||||
existing.PublicModel = pm
|
||||
}
|
||||
if rg := strings.TrimSpace(req.RouteGroup); rg != "" {
|
||||
existing.RouteGroup = groupx.Normalize(rg)
|
||||
}
|
||||
if st := strings.TrimSpace(req.Status); st != "" {
|
||||
existing.Status = st
|
||||
}
|
||||
if t := strings.TrimSpace(req.SelectorType); t != "" {
|
||||
existing.SelectorType = t
|
||||
}
|
||||
if req.SelectorValue != "" {
|
||||
existing.SelectorValue = strings.TrimSpace(req.SelectorValue)
|
||||
}
|
||||
|
||||
if err := h.db.Save(&existing).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update binding", "details": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.sync.SyncBindings(h.db); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sync bindings", "details": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, existing)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user