fix(api): add snake_case json tags to Endpoint/Task/request bodies for frontend contract
Go's encoding/json does not bridge snake_case <-> PascalCase field names, so store.Endpoint, store.Task and the anonymous request bodies in accounts.go/auth.go were silently decoding empty/zero values from the frontend's snake_case JSON contract (tls_mode, role_label, src_endpoint_id, dst_endpoint_id, src_login/pass, dst_login/pass). Adds explicit json tags; DB layer is unaffected since pgx binds by positional params, not struct-tag reflection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MMHQTtnQtQqL8muAXHr9kd
This commit is contained in:
@@ -40,7 +40,10 @@ func (s *Server) handleCreateAccount(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var body struct {
|
var body struct {
|
||||||
SrcLogin, SrcPass, DstLogin, DstPass string
|
SrcLogin string `json:"src_login"`
|
||||||
|
SrcPass string `json:"src_pass"`
|
||||||
|
DstLogin string `json:"dst_login"`
|
||||||
|
DstPass string `json:"dst_pass"`
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||||
http.Error(w, "bad json", http.StatusBadRequest)
|
http.Error(w, "bad json", http.StatusBadRequest)
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ func NewServer(cfg config.Config, s *store.Store, orch *orchestrator.Orchestrato
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
var body struct{ User, Pass string }
|
var body struct {
|
||||||
|
User string `json:"user"`
|
||||||
|
Pass string `json:"pass"`
|
||||||
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||||||
http.Error(w, "bad json", http.StatusBadRequest)
|
http.Error(w, "bad json", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package store
|
|||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
type Endpoint struct {
|
type Endpoint struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
RoleLabel string
|
RoleLabel string `json:"role_label"`
|
||||||
Host string
|
Host string `json:"host"`
|
||||||
Port int
|
Port int `json:"port"`
|
||||||
TLSMode string
|
TLSMode string `json:"tls_mode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) CreateEndpoint(ctx context.Context, e Endpoint) (int64, error) {
|
func (s *Store) CreateEndpoint(ctx context.Context, e Endpoint) (int64, error) {
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEndpointJSONRoundTrip(t *testing.T) {
|
||||||
|
var e Endpoint
|
||||||
|
if err := json.Unmarshal([]byte(`{"role_label":"src","host":"h","port":993,"tls_mode":"ssl"}`), &e); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if e.RoleLabel != "src" || e.Host != "h" || e.Port != 993 || e.TLSMode != "ssl" {
|
||||||
|
t.Fatalf("decode failed: %+v", e)
|
||||||
|
}
|
||||||
|
b, _ := json.Marshal(e)
|
||||||
|
if !strings.Contains(string(b), `"tls_mode":"ssl"`) || !strings.Contains(string(b), `"role_label":"src"`) {
|
||||||
|
t.Fatalf("marshal not snake_case: %s", b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTaskJSONRoundTrip(t *testing.T) {
|
||||||
|
var tk Task
|
||||||
|
if err := json.Unmarshal([]byte(`{"name":"n","src_endpoint_id":1,"dst_endpoint_id":2}`), &tk); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if tk.Name != "n" || tk.SrcEndpointID != 1 || tk.DstEndpointID != 2 {
|
||||||
|
t.Fatalf("decode failed: %+v", tk)
|
||||||
|
}
|
||||||
|
b, _ := json.Marshal(tk)
|
||||||
|
if !strings.Contains(string(b), `"src_endpoint_id":1`) {
|
||||||
|
t.Fatalf("marshal not snake_case: %s", b)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,12 +3,12 @@ package store
|
|||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
ID int64
|
ID int64 `json:"id"`
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
SrcEndpointID int64
|
SrcEndpointID int64 `json:"src_endpoint_id"`
|
||||||
DstEndpointID int64
|
DstEndpointID int64 `json:"dst_endpoint_id"`
|
||||||
Status string
|
Status string `json:"status"`
|
||||||
FolderMapping map[string]string
|
FolderMapping map[string]string `json:"folder_mapping"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Store) CreateTask(ctx context.Context, t Task) (int64, error) {
|
func (s *Store) CreateTask(ctx context.Context, t Task) (int64, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user