Search code examples
goif-statementstructure

Go Struct Fields Undefined


Learning Go as I work through creating a REST API. Getting the error undefined: authDetails when I use it the two times at the bottom to access the fields. I understand that it's set in a branch that may not be executed. I've tried moving it outside of the branch, or declaring it above with var authDetails auth.AccessDetails and then setting the values afterwards. I've also tried moving the assignment outside of the braces, but no matter what I do it doesn't seem to carry the values from within the conditional block out to where I try to use them.

I think I'm misunderstanding something regarding scope, if someone could assist me in understanding what the problem is it would be a huge help.

The Struct definition is:

type AccessDetails struct {
    AccessUuid string
    UserId   uint64
}

and the code is:

func (server *Server) GetTokenUserIDFromRequest(r *http.Request) (uint64, error) {
    var authDetails auth.AccessDetails
    tokenString := auth.ExtractToken(r)
    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return 0, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
        }
        return []byte(os.Getenv("API_SECRET")), nil
    })
    if err != nil {
        return 0, err
    }
    claims, ok := token.Claims.(jwt.MapClaims)
    if ok && token.Valid {
        accessUuid, ok := claims["access_uuid"].(string)
        if !ok {
            return 0, errors.New("token not valid, cannot retrieve access_uuid")
        }
        userid, err := strconv.ParseUint(fmt.Sprintf("%.0f", claims["user_id"]), 10, 64)
        if err != nil {
            return 0, err
        }

        authDetails := &auth.AccessDetails{
            AccessUuid: accessUuid,
            UserId: userid,
        }
    }
    
    redisuserid, err := server.RedisClient.Get(authDetails.AccessUuid).Result()
    if err != nil {
        return 0, err
    }
    userID, _ := strconv.ParseUint(redisuserid, 10, 64)
    if userID != authDetails.UserId {
        return 0, errors.New("userid from token does not match userid from database")
    }
    return userID, nil
}

Solution

  • You are redeclaring authDetails in the if-block instead of setting the value declared at the outer scope. The relevant section in the language specification is:

    https://golang.org/ref/spec#Short_variable_declarations

    Instead of authDetails:=... use authDetails=..., so it becomes an assignment, not a declaration.