How do I parse out the Identity Traits `interface{...
# talk-kratos
p
How do I parse out the Identity Traits
interface{}
from a Session when using the golang bindings?
e
I do the following to extract a
[]string
from metadata
Copy code
groups := func (i []interface{}) []string {
			var roles []string
			for _, role := range i {
				if v, ok := role.(string); ok {
					roles = append(roles, v)
				}
			}
			return roles
		}(sess.Identity.MetadataPublic["roles"].([]interface{}))
p
When I
%+v
print the Traits, I get
map[email:<mailto:ops@example.net|ops@example.net> username:ops]
. When I attempt to typecast that to a struct with the appropriate fields, it fails.
Copy code
type IdentityTraits struct {         
    Email    string `json:"email"`   
    Username string `json:"username"`
}

traits, ok := id.Traits.(IdentityTraits)                  
if !ok {                                                  
    return nil, fmt.Errorf("Unknown identity traits type")
}
ok
always is false here. I've tried other typecasts as well like
map[string]string
.
This worked. Looks like you need to treat Traits as
map[string]interface{}
. If you have a trait of "email":
Copy code
traits, ok := id.Traits.(map[string]interface{})          
if !ok {                                                  
    return nil, fmt.Errorf("Unknown identity traits type")
}                                                         

email := ""
if val, ok := traits["email"]; ok { 
    r, ok := val.(string)       
    if ok {                 
       email = r
    }    
}

// email here is the value in Traits if it exists.
e
hmm what type is it showing? Odds are is that it is a
map[string]string
or
map[string]interface{}
so you would need to do something like
Copy code
traits, _ := id.Traits.(map[string]string)
email, _ := traits["email"]
or
Copy code
email := id.Traits.(map[string]interface{})["email"].(string)
where you first convert
id.Traits
from
interface{}
to either
map[string]interface{}/string
haha looks like we came to the same solution 🙂 happy to see!
p
Yeah. 🙂
It seems like there should be a better way given that there is typed JSON involved.
And you have access to the json schema.
ty for the help, @echoing-caravan-91564.
e
I think its to do with map funny enough I do have something about this written from last week
Copy code
// TODO make radar model of user traits as defined in ory identity schema & metadata we define ourselves
	// it would be helpful to have a fully capable go model if we want more control
	// schema isn't expected to change, so we don't need to automate it for now
	// easy way is to use json can just be parsed to Go <https://transform.tools/json-to-go>
	// we could use @go:generate (<https://blog.carlmjohnson.net/post/2016-11-27-how-to-use-go-generate/>)
	// use go toolchain to guarantee install of json-to-go <https://github.com/samit22/json-go>
	//
	// a good generator would
	// - be checked on PR that it matches generated output similar to protos
	// - have add ory to our IaaS and use ci to regenerate on change
	//
	// I don't know why I spent the 10 min writing this out
p
Yeah, that looks ok.
e
I would wager if you could convert to map[string]string the json would work
p
@high-optician-2097 Is there a cleaner way to parse incoming
Identity.Traits
?
I tried that and it did not seem to work.
I guess the type in the Traits is exactly what you give to
ory.AdminCreateIdentityBody
which makes sense.
So the
map[string]interface{}
must come from the auto-generated api. So this is in the API spec somewhere I guess.
s
you could first marshal the traits as JSON again, and then unmarshal to your struct
i.e.
Copy code
type Traits struct { Email string `json:"email"` }
enc, err := json.Marshal(id.Traits)
var traits Traits
err = json.Unmarshal(enc, &traits)
but yeah, as you figured out, it is a problem with the autogenerated sdk
ideally it would not unmarshal the traits, but provide them as
json.RawMessage
instead of
map[string]interface{}
, but I don't know of a way to do that
the last possibility I can think of is generating your own sdk from the spec after patching the traits to be your schema
but that is all I can help, this is just something we use internally so no official support I'm afraid
p
thanks for the response.