-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserialization_groups_test.go
More file actions
135 lines (108 loc) · 4.14 KB
/
serialization_groups_test.go
File metadata and controls
135 lines (108 loc) · 4.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package example_test
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/philiphil/restman/configuration"
"github.com/philiphil/restman/orm"
"github.com/philiphil/restman/orm/entity"
"github.com/philiphil/restman/orm/gormrepository"
"github.com/philiphil/restman/route"
"github.com/philiphil/restman/router"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
//Serialization groups are an easy way to control which fields are included in API responses and requests based on context.
// In this example, we define "read" and "write" groups to manage field visibility during GET and POST/PUT operations respectively.
// With SerializationGroups configuration , as with any configuration we can set router-wide defaults that can be overridden on a operation level
// we also provide client control over group overwriting via query parameters.
type SerialProduct struct {
entity.BaseEntity
Name string `json:"name" groups:"read,write"`
Price float64 `json:"price" groups:"write"`
InternalSKU string `json:"internal_sku" groups:"read"` //should be never editable
CostPrice float64 `json:"cost_price" groups:"private_stuff"` //should be never visible via api
}
func (p SerialProduct) GetId() entity.ID { return p.Id }
func (p SerialProduct) SetId(id any) entity.Entity {
p.Id = entity.CastId(id)
return p
}
func (p SerialProduct) ToEntity() SerialProduct { return p }
func (p SerialProduct) FromEntity(e SerialProduct) any { return e }
func getSerialProductDB() *gorm.DB {
db, err := gorm.Open(sqlite.Open("file:serial_product_test?mode=memory&cache=shared&_fk=1"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
CreateBatchSize: 1000,
})
if err != nil {
panic(err)
}
return db
}
func TestSerializationGroupsReadWrite(t *testing.T) {
db := getSerialProductDB()
db.AutoMigrate(&SerialProduct{})
r := gin.New()
r.Use(gin.Recovery())
routes := route.DefaultApiRoutes()
routes[route.Post].Configuration[configuration.InputSerializationGroupsType] = configuration.InputSerializationGroups("write")
productRouter := router.NewApiRouter(
*orm.NewORM(gormrepository.NewRepository[SerialProduct](db)),
routes,
configuration.OutputSerializationGroups("read"), //default router-wide serialization group should be "read"
)
productRouter.AllowRoutes(r)
postData := SerialProduct{
Name: "Laptop",
Price: 999.99,
CostPrice: 700.00,
InternalSKU: "SKU-IGNORED",
}
jsonData, _ := json.Marshal(postData)
w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/api/serial_product", bytes.NewBuffer(jsonData))
req.Header.Set("Content-Type", "application/json")
r.ServeHTTP(w, req)
if w.Code != http.StatusCreated {
t.Errorf("Expected status 201, got %d. Body: %s", w.Code, w.Body.String())
}
var createdProduct SerialProduct
db.First(&createdProduct, 1)
if createdProduct.Name != "Laptop" {
t.Errorf("Name should have been written, got: %s", createdProduct.Name)
}
if createdProduct.Price != 999.99 {
t.Errorf("Price should have been written to DB, got: %f", createdProduct.Price)
}
if createdProduct.InternalSKU == "SKU-IGNORED" {
t.Error("InternalSKU should not have been written (not in write group)")
}
if createdProduct.CostPrice == 700.00 {
t.Error("CostPrice should not have been written (not in write group)")
}
w = httptest.NewRecorder()
req, _ = http.NewRequest("GET", "/api/serial_product/1", nil)
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Errorf("Expected status 200, got %d", w.Code)
}
var response SerialProduct
json.Unmarshal(w.Body.Bytes(), &response)
if response.Name != "Laptop" {
t.Error("Name should be visible in GET response (read group)")
}
if response.Price != 0 {
t.Errorf("Price should NOT be visible in GET response (write group only), got: %f", response.Price)
}
if response.InternalSKU != "" {
t.Errorf("InternalSKU should be empty in GET (read group but never written), got: %s", response.InternalSKU)
}
if response.CostPrice != 0 {
t.Errorf("CostPrice should be zero in GET (private_stuff group not included), got: %f", response.CostPrice)
}
}