fix(#41): expose rawJson in detail response, not just storage

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
QiuSW
2026-08-19 14:42:46 +08:00
co-authored by Claude Opus 5
parent 3b27d19aa8
commit f72c24b5da
2 changed files with 44 additions and 4 deletions
+15 -4
View File
@@ -84,15 +84,26 @@ func (service *Service) List(ctx context.Context, request ListRequest) (ListResp
return ListResponse{Items: items, Total: total, Page: request.Page, PageSize: request.PageSize}, nil
}
func (service *Service) Detail(ctx context.Context, id uint64) (models.SYBProduct, error) {
// DetailView exposes RawJSON, which the model deliberately keeps json:"-" so
// List (and any other place a bare models.SYBProduct gets serialized) never
// leaks the full raw payload by accident. This was caught before it shipped:
// the Detail handler used to serialize the bare model directly, which meant
// RawJSON — required by #41 ("原始JSON和结构化字段均可在详情查看") — was
// silently unreachable through the API despite being stored correctly.
type DetailView struct {
models.SYBProduct
RawJSON string `json:"rawJson"`
}
func (service *Service) Detail(ctx context.Context, id uint64) (DetailView, error) {
var record models.SYBProduct
if err := service.DB.WithContext(ctx).First(&record, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return models.SYBProduct{}, notFound()
return DetailView{}, notFound()
}
return models.SYBProduct{}, internalError(err)
return DetailView{}, internalError(err)
}
return record, nil
return DetailView{SYBProduct: record, RawJSON: record.RawJSON}, nil
}
type ReparseRequest struct {
@@ -2,7 +2,9 @@ package sybimport_test
import (
"context"
"encoding/json"
"errors"
"strings"
"testing"
"go-admin/app/goauto/models"
@@ -105,3 +107,30 @@ func TestServiceManualCorrectTrimsWhitespace(t *testing.T) {
t.Fatalf("expected trimmed values, got %q/%q", record.TargetColor, record.TargetSize)
}
}
// Regression test: Detail previously returned the bare model, whose RawJSON
// field is json:"-" (to keep List from leaking it). That made the raw
// payload silently unreachable through the API despite #41 requiring it in
// the detail view. DetailView must carry it under a real JSON key.
func TestServiceDetailExposesRawJSON(t *testing.T) {
db := openTestDB(t)
applied, err := sybimport.ApplyDetail(context.Background(), db, realOrder(), realDetailA())
if err != nil {
t.Fatalf("apply: %v", err)
}
service := sybimport.NewService(db)
detail, err := service.Detail(context.Background(), applied.SYBProduct.ID)
if err != nil {
t.Fatalf("detail: %v", err)
}
if detail.RawJSON == "" || detail.RawJSON == "{}" {
t.Fatalf("expected the real raw payload, got %q", detail.RawJSON)
}
encoded, err := json.Marshal(detail)
if err != nil {
t.Fatalf("marshal: %v", err)
}
if !strings.Contains(string(encoded), `"rawJson"`) {
t.Fatalf("serialized detail must expose rawJson, got %s", encoded)
}
}