-
Notifications
You must be signed in to change notification settings - Fork 0
/
binder.go
123 lines (109 loc) · 3.04 KB
/
binder.go
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
// Copyright 2021 Kévin José. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package easyapi
import (
"fmt"
"net/http"
"reflect"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
"gitlab.com/kjose/jgmc/api/internal/easyapi/db/dao"
"gitlab.com/kjose/jgmc/api/internal/easyapi/layer"
)
var (
BinderConfig = &binderConfig{
// If true the body will be kept in the context key gin.BodyBytesKey
KeepBody: false,
}
)
// Binder config
type binderConfig struct {
KeepBody bool
}
// Create a new validation error from a tag and a field
func NewValidationError(tag string, field string, resource interface{}) layer.ValidationError {
message := fmt.Sprintf("Field %s failed with condition `%s`", field, tag)
if m, ok := resource.(layer.ValidationAwareInterface); ok {
if customMessage, ok := m.GetCustomValidationMessages()[fmt.Sprintf("%s:%s", field, tag)]; ok {
message = customMessage
}
}
return layer.ValidationError{
Tag: tag,
Field: field,
Message: message,
}
}
// Bind and validate recursively a request body to a resource
func BindAndValidate(c *gin.Context, i interface{}) error {
// request validation
validationErrors := []layer.ValidationError{}
var err error
if BinderConfig.KeepBody {
err = c.ShouldBindBodyWith(i, binding.JSON)
} else {
err = c.ShouldBindJSON(i)
}
if err != nil {
if ve, ok := err.(validator.ValidationErrors); ok {
for _, e := range ve {
validationErrors = append(validationErrors, NewValidationError(e.Tag(), e.Field(), i))
}
} else {
validationErrors = append(validationErrors, NewValidationError("", err.Error(), i))
}
}
if iv, ok := i.(layer.ValidationAwareInterface); ok {
validationErrors = append(validationErrors, iv.Validate()...)
}
if len(validationErrors) > 0 {
return HttpError(c, http.StatusBadRequest, "Validation errors", validationErrors)
}
// uuid bindings
err = AppendBindings(i)
if err != nil {
return HttpError(c, http.StatusNotFound, err.Error(), nil)
}
return nil
}
// Append bindings based on GetUUIDBindings resource method
func AppendBindings(item interface{}) error {
if ib, ok := item.(layer.UUIDBinderInterface); ok {
for _, b := range ib.GetUUIDBindings() {
if b.UUID == nil {
continue
}
_, err := dao.GetResourceDAO(b.BindTo).FindById(b.BindTo, b.UUID.String())
if err != nil {
return fmt.Errorf("%s not found", b.Name)
}
// recursive
if bb, ok := b.BindTo.(layer.UUIDBinderInterface); ok {
err := AppendBindings(bb)
if err != nil {
return err
}
}
}
}
return nil
}
// Remove bindings of a resource
func RemoveUUIDBindings(item interface{}) {
if ib, ok := item.(layer.UUIDBinderInterface); ok {
for _, b := range ib.GetUUIDBindings() {
if b.UUID == nil {
continue
}
v := reflect.ValueOf(b.BindTo)
p := v.Elem()
p.Set(reflect.Zero(p.Type()))
// recursive
if bb, ok := b.BindTo.(layer.UUIDBinderInterface); ok {
RemoveUUIDBindings(bb)
}
}
}
}