Files
wild-central/internal/api/v1/handlers_services.go
Paul Payne 909527f060 feat: Add tests for config, secrets, services, and cloudflare endpoints
Fix config endpoint to return wrapped { configured, config } response
that the web UI expects. Fix services handler to return stored version
with defaults applied.

New tests:
- GetGlobalConfig: wrapped response, empty/not-configured case
- GetGlobalSecrets: leaf redaction preserves structure, raw mode
- UpdateGlobalConfig: write and verify
- CloudflareVerify: no-token case
- Services: register, list, get, update, deregister, TCP passthrough
  defaults, validation errors

15 new test cases, all passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-07-09 04:45:55 +00:00

97 lines
2.6 KiB
Go

package v1
import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/wild-cloud/wild-central/internal/services"
)
// ServicesListAll lists all registered services.
func (api *API) ServicesListAll(w http.ResponseWriter, r *http.Request) {
svcs, err := api.services.List()
if err != nil {
respondError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to list services: %v", err))
return
}
if svcs == nil {
svcs = []services.Service{}
}
respondJSON(w, http.StatusOK, map[string]any{
"services": svcs,
})
}
// ServicesGet retrieves a service by name.
func (api *API) ServicesGet(w http.ResponseWriter, r *http.Request) {
name := mux.Vars(r)["name"]
svc, err := api.services.Get(name)
if err != nil {
respondError(w, http.StatusNotFound, fmt.Sprintf("Service not found: %v", err))
return
}
respondJSON(w, http.StatusOK, svc)
}
// ServicesRegister creates or updates a service registration.
func (api *API) ServicesRegister(w http.ResponseWriter, r *http.Request) {
var svc services.Service
if err := json.NewDecoder(r.Body).Decode(&svc); err != nil {
respondError(w, http.StatusBadRequest, fmt.Sprintf("Invalid request body: %v", err))
return
}
if err := api.services.Register(svc); err != nil {
respondError(w, http.StatusBadRequest, fmt.Sprintf("Failed to register service: %v", err))
return
}
// Return the stored version (has defaults applied)
stored, _ := api.services.Get(svc.Name)
respondJSON(w, http.StatusCreated, map[string]any{
"message": fmt.Sprintf("Service %q registered", svc.Name),
"service": stored,
})
}
// ServicesUpdate applies partial updates to a service.
func (api *API) ServicesUpdate(w http.ResponseWriter, r *http.Request) {
name := mux.Vars(r)["name"]
var updates map[string]any
if err := json.NewDecoder(r.Body).Decode(&updates); err != nil {
respondError(w, http.StatusBadRequest, fmt.Sprintf("Invalid request body: %v", err))
return
}
if err := api.services.Update(name, updates); err != nil {
respondError(w, http.StatusNotFound, fmt.Sprintf("Failed to update service: %v", err))
return
}
svc, _ := api.services.Get(name)
respondJSON(w, http.StatusOK, map[string]any{
"message": fmt.Sprintf("Service %q updated", name),
"service": svc,
})
}
// ServicesDeregister removes a service registration.
func (api *API) ServicesDeregister(w http.ResponseWriter, r *http.Request) {
name := mux.Vars(r)["name"]
if err := api.services.Deregister(name); err != nil {
respondError(w, http.StatusNotFound, fmt.Sprintf("Failed to deregister service: %v", err))
return
}
respondMessage(w, http.StatusOK, fmt.Sprintf("Service %q deregistered", name))
}