-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstripper.go
66 lines (60 loc) · 2.08 KB
/
stripper.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
// Package stripper provides functions to remove values from specified struct fields, e.g. to reduce the risk of sending protected attributes in a JSON-response in an API.
//
// Use this package if you wish to still be able to easily perform an unmarshalling of a JSON-string to a struct, but still wanting to be able to prevent sensitive data to be Marshalled by mistake.
//
// Examples of struct field tags and their meanings:
// // Field will be set to the Zero value (reflect.Zero)
// Field int `clean:"true"`
//
// // Nested Struct will also be checked (as specified by those struct field tags)
// Field Struct `clean:"true"`
// All other values than 'true' will make the cleaner ignore that field
package stripper
import (
"encoding/json"
"errors"
"reflect"
)
const tagName = "clean"
//Marshal removes (setting to default Zero value) any data on struct fields with the tag `clean:"true"` on them, but leaves the rest, and then calls json.Marshal
func Marshal(a interface{}) ([]byte, error) {
v := reflect.ValueOf(a)
if v.Kind() != reflect.Ptr {
return []byte{}, errors.New("must provide a pointer")
}
cpy := clean(v)
return json.Marshal(cpy)
}
//MarshalIndent returns a cleaned json marshalled response
func MarshalIndent(a interface{}, prefix, indent string) ([]byte, error) {
v := reflect.ValueOf(a)
if v.Kind() != reflect.Ptr {
return []byte{}, errors.New("must provide a pointer")
}
cpy := clean(v)
return json.MarshalIndent(cpy, prefix, indent)
}
//Clean modifies the interface given and returns the cleaned version, the response must be type asserted
func Clean(a interface{}) (interface{}, error) {
v := reflect.ValueOf(a)
if v.Kind() != reflect.Ptr {
return nil, errors.New("must provide a pointer")
}
cpy := clean(v)
return cpy, nil
}
func clean(v reflect.Value) interface{} {
in := reflect.Indirect(v)
for i := 0; i < in.NumField(); i++ {
tag := in.Type().Field(i).Tag.Get(tagName)
if tag != "true" {
continue
}
if in.Field(i).Kind() == reflect.Struct {
clean(in.Field(i))
continue
}
in.Field(i).Set(reflect.Zero(in.Field(i).Type()))
}
return v.Interface()
}