I am handling user auth data posted to my Go backend through an HTML form. I am building on some boilerplate to learn Go better.
My problem is what the following func
returns:
func (ctrl UserController) Signin(c *gin.Context) {
var signinForm forms.SigninForm
user, err := userModel.Signin(signinForm)
if err := c.ShouldBindWith(&signinForm, binding.Form); err != nil {
c.JSON(406, gin.H{"message": "Invalid signin form", "form": signinForm})
c.Abort()
return
}
if err == nil {
session := sessions.Default(c)
session.Set("user_id", user.ID)
session.Set("user_email", user.Email)
session.Set("user_name", user.Name)
session.Save()
c.JSON(200, gin.H{"message": "User signed in", "user": user})
} else {
c.JSON(406, gin.H{"message": "Invalid signin details", "error": err.Error()})
}
}
The first if
statement validates the input, and that works fine (error if the email isn't in proper email format, no error if it is). However, if input is properly validated, the else
clause of the second statement is triggered, and the following JSON is returned:
{
error: "sql: no rows in result set",
message: "Invalid signin details"
}
It is probably useful to also post the relevant code in my User
model:
//User ...
type User struct {
ID int `db:"id, primarykey, autoincrement" json:"id"`
Email string `db:"email" json:"email"`
Password string `db:"password" json:"-"`
Name string `db:"name" json:"name"`
UpdatedAt int64 `db:"updated_at" json:"updated_at"`
CreatedAt int64 `db:"created_at" json:"created_at"`
}
//UserModel ...
type UserModel struct{}
//Signin ...
func (m UserModel) Signin(form forms.SigninForm) (user User, err error) {
err = db.GetDB().SelectOne(&user, "SELECT id, email, password, name, updated_at, created_at FROM public.user WHERE email=LOWER($1) LIMIT 1", form.Email)
if err != nil {
return user, err
}
bytePassword := []byte(form.Password)
byteHashedPassword := []byte(user.Password)
err = bcrypt.CompareHashAndPassword(byteHashedPassword, bytePassword)
if err != nil {
return user, errors.New("Invalid password")
}
return user, nil
}
How do I resolve the sql: no rows in result set
error?
You should change the order of operations in your code. At first you need to get data from request with if err := c.ShouldBindWith(&signinForm, binding.Form); err != nil {
and after that you need to try get data from database with user, err := userModel.Signin(signinForm)
There are good reasons for this. Ideally it tries to read paths by the separator, meaning /path/abcd/
and /path/abcd
are different. abcd
IS the resource in the latter while the resource lies somewhere within abcd
in the former. With that in mind, then it will not be able to route properly to /path/abcd
if you also have a path /path
as well. In order to remove that ambiguity as to which handler to use, you need to mention the handler for the more specific path ie, /path/abcd
before the more generic one /path
.