Created
May 20, 2020 05:14
-
-
Save acoshift/442893609e1f5c8b6c714982212197f4 to your computer and use it in GitHub Desktop.
[Golang] Mask struct by role using struct tag
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"os" | |
"reflect" | |
"strings" | |
) | |
type response struct { | |
ID string `json:"id"` | |
Username string `json:"username"` | |
Password string `json:"password,omitempty" role:"admin"` | |
Info *info `json:"info,omitempty" role:"admin,officer"` | |
} | |
type info struct { | |
FirstName string `json:"first_name,omitempty" role:"admin,officer"` | |
LastName string `json:"last_name"` | |
} | |
func makeResponse() *response { | |
return &response{ | |
ID: "10", | |
Username: "user1", | |
Password: "1234", | |
Info: &info{ | |
FirstName: "AAA", | |
LastName: "BBB", | |
}, | |
} | |
} | |
// $ go run main.go | |
// Raw struct: | |
// {"id":"10","username":"user1","password":"1234","info":{"first_name":"AAA","last_name":"BBB"}} | |
// Mask for admin: | |
// {"id":"10","username":"user1","password":"1234","info":{"first_name":"AAA","last_name":"BBB"}} | |
// Mask for marketing: | |
// {"id":"10","username":"user1"} | |
// Mask for officer: | |
// {"id":"10","username":"user1","info":{"first_name":"AAA","last_name":"BBB"}} | |
func main() { | |
r := makeResponse() | |
fmt.Println("Raw struct:") | |
json.NewEncoder(os.Stdout).Encode(r) | |
maskResponse(r, "admin") | |
fmt.Println("Mask for admin:") | |
json.NewEncoder(os.Stdout).Encode(r) | |
r = makeResponse() | |
fmt.Println("Mask for marketing:") | |
maskResponse(r, "marketing") | |
json.NewEncoder(os.Stdout).Encode(r) | |
r = makeResponse() | |
fmt.Println("Mask for officer:") | |
maskResponse(r, "officer") | |
json.NewEncoder(os.Stdout).Encode(r) | |
} | |
// v must be pointer of struct | |
func maskResponse(v interface{}, role string) { | |
rv := reflect.ValueOf(v).Elem() | |
rt := reflect.TypeOf(v).Elem() | |
for i := 0; i < rt.NumField(); i++ { | |
ft := rt.Field(i) | |
r := ft.Tag.Get("role") | |
// allow for all role | |
if r == "" { | |
// nest struct | |
if ft.Type.Kind() == reflect.Struct { | |
maskResponse(rv.Field(i).Addr().Interface(), role) | |
} | |
continue | |
} | |
rs := strings.Split(r, ",") | |
// not allow | |
if !stringsContain(rs, role) { | |
rv.Field(i).Set(reflect.New(ft.Type).Elem()) | |
continue | |
} | |
// allow but might not allow inside nest struct | |
if ft.Type.Kind() == reflect.Struct { | |
maskResponse(rv.Field(i).Addr().Interface(), role) | |
} | |
} | |
} | |
func stringsContain(xs []string, x string) bool { | |
for _, p := range xs { | |
if p == x { | |
return true | |
} | |
} | |
return false | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment