This is my first question regarding GoLang please be gentle. I am building a test JSON API.
I have a type struct named User
type User struct {
UserID int
Email string
FirstName string
LastName string
PasswordHash string
}
In middleware, I verify JWT token is valid and if so, I load entire record of User and save it in the context so that it is available in handlers under.
So in middleware, I save User struct like this
context.Set(r, "User", *User)
fmt.Println(*User)
next.ServeHTTP(w, r)
Output of Println is
{12 sallu@domain.com.au Mr. Sallu $2a$14oUg3d1rm./.B/vUyhYR9/hlHfagE4tGicNc14EWK3u }
Then in the final handler I access this context and get User object.
User := context.Get(r, "User")
fmt.Println("---User---", fmt.Sprintf(" %T ", User))
fmt.Println(User)
Output of Println is
---User--- models.User
{12 sallu@domain.com.au Mr. Sallu $2a$14oUg3d1rm./.B/vUyhYR9/hlHfagE4tGicNc14EWK3u }
The issue is that in Controller when I access User.Email I am getting an error
User.Email undefined (type interface {} is interface with no methods)
How can I fix this..? I want to use User.Email or User.UserID. Seems like context is doing something to it.
Please help
Everywhere in your code please use different names for variable and type.
e.g. keep type User
and variable user
.
In your controller, type assert your user
back to User
.
if u, ok := user.(User); ok {
fmt.Println(u.Email)
}
User.Email
is a little ambiguous there. You're using the same name, User
for both the type definition and a variable. However, the error message you're seeing:
User.Email undefined (type interface {} is interface with no methods)
shows that the compiler is understanding User
there to be the variable, because it thinks the type is interface{}
-- the generic type in Go.
And the error message you're seeing is slightly different from what I get if I don't use a variable at all, but just try to access a method that doesn't exist on a type, e.g.:
package main
import(
"fmt"
)
type User struct {
Email string
}
func main() {
fmt.Println(User.Email)
}
When executed prints this error:
User.Email undefined (type User has no method Email)
Still, it would be best if you changed your variable name to be different from your type name, e.g.
u := context.Get(r, "User")
And then you would access u.Email
Given that the compiler is seeing your variable as type interface{}
rather than type User
, biosckon may be correct that you are missing a type assertion after you extracted from context. See the go blog on context, especially:
FromContext extracts a userIP from a Context:
func FromContext(ctx context.Context) (net.IP, bool) {
// ctx.Value returns nil if ctx has no value for the key;
// the net.IP type assertion returns ok=false for nil.
userIP, ok := ctx.Value(userIPKey).(net.IP)
return userIP, ok
}
See also this Stackoverflow question and answer on fetching values from context, especially:
You need to set and extract the value with the correct type as well...I often times define helper functions to extract the context values and do the type assertion
What's strange about that is the output of your print statements, which make it look like you have the right type. But again that's a little ambiguous since you're using the same name for a variable and a type. And -- it doesn't look like you shared all your code -- are those prints from the scope where you first set them rather than after extracting from context in a different scope? If so, that would explain the difference.