Skip to content

Commit

Permalink
refactor: http error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
crazyoptimist committed Jun 16, 2024
1 parent 0786ef7 commit cb106d7
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 99 deletions.
5 changes: 2 additions & 3 deletions internal/domain/auth/jwt.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package auth

import (
"net/http"
"errors"
"strconv"
"time"

"github.com/golang-jwt/jwt/v5"

"gin-starter/internal/config"
"gin-starter/pkg/common"
"gin-starter/pkg/utils"
)

const (
Expand Down Expand Up @@ -106,7 +105,7 @@ func ValidateToken(tokenString string) (isValid bool, userId uint, keyId uint, e
}

if !token.Valid {
err = &utils.HttpError{Code: http.StatusUnauthorized, Message: "Invalid Token"}
err = errors.New("Invalid JWT token")
return
}

Expand Down
15 changes: 6 additions & 9 deletions internal/domain/auth/service.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package auth

import (
"errors"
"fmt"
"net/http"

"gin-starter/internal/domain/model"
"gin-starter/internal/domain/user"
Expand Down Expand Up @@ -30,14 +30,11 @@ func NewAuthService(userRepository user.UserRepository, authHelper AuthHelper) *

func (s *AuthService) Register(registerDto *RegisterDto) (*LoginResponse, error) {
if _, err := s.UserRepository.FindByEmail(registerDto.Email); err == nil {
return nil, &utils.HttpError{
Code: http.StatusBadRequest,
Message: "Account already exists with the email",
}
return nil, errors.New("Account already exists with the same email")
}

if registerDto.Password != registerDto.PasswordConfirmation {
return nil, &utils.HttpError{Code: http.StatusBadRequest, Message: "Password mismatched"}
return nil, errors.New("Password mismatched")
}

if hashedPassword, err := utils.HashPassword(registerDto.Password); err != nil {
Expand Down Expand Up @@ -74,7 +71,7 @@ func (s *AuthService) Login(loginDto *LoginDto) (*LoginResponse, error) {
}

if err := utils.VerifyPassword(user.Password, loginDto.Password); err != nil {
return nil, &utils.HttpError{Code: http.StatusUnauthorized, Message: "Invalid password"}
return nil, errors.New("Invalid password")
}

accessToken, refreshToken, err := GenerateTokenPair(user.ID)
Expand All @@ -97,11 +94,11 @@ func (s *AuthService) RefreshToken(logoutDto *LogoutDto) (*LoginResponse, error)
}

if !isTokenValid {
return nil, fmt.Errorf("Refresh token is invalid")
return nil, errors.New("Invalid refresh token")
}

if keyId != RefreshTokenKeyId {
return nil, fmt.Errorf("Wrong key ID")
return nil, errors.New("Invalid key ID")
}

isTokenBlacklisted, err := s.AuthHelper.IsTokenBlacklisted(logoutDto.RefreshToken)
Expand Down
38 changes: 19 additions & 19 deletions internal/infrastructure/controller/auth_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"gin-starter/internal/domain/auth"
"gin-starter/internal/infrastructure/helper"
"gin-starter/internal/infrastructure/repository"
"gin-starter/pkg/utils"
"gin-starter/pkg/common"
)

type authController struct {
Expand All @@ -30,19 +30,19 @@ func NewAuthController(db *gorm.DB) *authController {
// @Tags auth
// @Param request body auth.RegisterDto true "RegisterDto"
// @Success 201 {object} auth.LoginResponse
// @Failure 400 {object} utils.HttpError
// @Failure 500 {object} utils.HttpError
// @Failure 400 {object} common.HttpError
// @Failure 500 {object} common.HttpError
// @Router /auth/register [post]
func (a *authController) Register(c *gin.Context) {
var registerDto auth.RegisterDto
if err := c.BindJSON(&registerDto); err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

loginResponse, err := a.AuthService.Register(&registerDto)
if err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}
loginResponse.ExpiresIn = config.Global.JwtAccessTokenExpiresIn.Seconds()
Expand All @@ -55,20 +55,20 @@ func (a *authController) Register(c *gin.Context) {
// @Tags auth
// @Param request body auth.LoginDto true "LoginDto"
// @Success 201 {object} auth.LoginResponse
// @Failure 400 {object} utils.HttpError
// @Failure 401 {object} utils.HttpError
// @Failure 404 {object} utils.HttpError
// @Failure 400 {object} common.HttpError
// @Failure 401 {object} common.HttpError
// @Failure 404 {object} common.HttpError
// @Router /auth/login [post]
func (a *authController) Login(c *gin.Context) {
var loginDto auth.LoginDto
if err := c.BindJSON(&loginDto); err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

loginResponse, err := a.AuthService.Login(&loginDto)
if err != nil {
utils.RaiseHttpError(c, http.StatusUnauthorized, err)
common.RaiseHttpError(c, http.StatusUnauthorized, err)
return
}
loginResponse.ExpiresIn = config.Global.JwtAccessTokenExpiresIn.Seconds()
Expand All @@ -80,19 +80,19 @@ func (a *authController) Login(c *gin.Context) {
// @Summary Logout user (Invalidates refresh token)
// @Tags auth
// @Success 200
// @Failure 401 {object} utils.HttpError
// @Failure 500 {object} utils.HttpError
// @Failure 401 {object} common.HttpError
// @Failure 500 {object} common.HttpError
// @Router /auth/logout [post]
// @Security JWT
func (a *authController) Logout(c *gin.Context) {
var logoutDto auth.LogoutDto
if err := c.BindJSON(&logoutDto); err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

if err := a.AuthService.Logout(&logoutDto); err != nil {
utils.RaiseHttpError(c, http.StatusInternalServerError, err)
common.RaiseHttpError(c, http.StatusInternalServerError, err)
return
}

Expand All @@ -104,23 +104,23 @@ func (a *authController) Logout(c *gin.Context) {
// @Tags auth
// @Param request body auth.LogoutDto true "TokenRefresh DTO"
// @Success 201 {object} auth.LoginResponse
// @Failure 400 {object} utils.HttpError
// @Failure 500 {object} utils.HttpError
// @Failure 400 {object} common.HttpError
// @Failure 500 {object} common.HttpError
// @Router /auth/refresh [post]
func (a *authController) RefreshToken(c *gin.Context) {
var refreshDto auth.LogoutDto
if err := c.BindJSON(&refreshDto); err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

refreshResponse, err := a.AuthService.RefreshToken(&refreshDto)
if err != nil {
if errors.Is(err, auth.ErrTokenBlacklisted) {
utils.RaiseHttpError(c, http.StatusUnauthorized, err)
common.RaiseHttpError(c, http.StatusUnauthorized, err)
return
}
utils.RaiseHttpError(c, http.StatusInternalServerError, err)
common.RaiseHttpError(c, http.StatusInternalServerError, err)
return
}

Expand Down
49 changes: 24 additions & 25 deletions internal/infrastructure/controller/user_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"gin-starter/internal/domain/user"
"gin-starter/internal/infrastructure/repository"
"gin-starter/pkg/common"
"gin-starter/pkg/utils"
)

const CACHE_KEY_PREFIX_USER = "user:"
Expand All @@ -30,7 +29,7 @@ func NewUserController(db *gorm.DB) *userController {
// @Summary Retrieves users
// @Tags users
// @Success 200 {array} model.User
// @Failure 500 {object} utils.HttpError
// @Failure 500 {object} common.HttpError
// @Router /users [get]
// @Security JWT
func (u *userController) FindAll(c *gin.Context) {
Expand All @@ -44,7 +43,7 @@ func (u *userController) FindAll(c *gin.Context) {
filterParams,
)
if err != nil {
utils.RaiseHttpError(c, http.StatusInternalServerError, err)
common.RaiseHttpError(c, http.StatusInternalServerError, err)
return
}

Expand All @@ -58,21 +57,21 @@ func (u *userController) FindAll(c *gin.Context) {
// @Tags users
// @Param id path integer true "User ID"
// @Success 200 {object} model.User
// @Failure 400 {object} utils.HttpError
// @Failure 404 {object} utils.HttpError
// @Failure 500 {object} utils.HttpError
// @Failure 400 {object} common.HttpError
// @Failure 404 {object} common.HttpError
// @Failure 500 {object} common.HttpError
// @Router /users/{id} [get]
// @Security JWT
func (u *userController) FindById(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

user, err := u.UserService.FindById(uint(id))
if err != nil {
utils.RaiseHttpError(c, http.StatusNotFound, err)
common.RaiseHttpError(c, http.StatusNotFound, err)
return
}

Expand All @@ -84,20 +83,20 @@ func (u *userController) FindById(c *gin.Context) {
// @Tags users
// @Param request body user.CreateUserDto true "CreateUserDto"
// @Success 201 {object} model.User
// @Failure 400 {object} utils.HttpError
// @Failure 500 {object} utils.HttpError
// @Failure 400 {object} common.HttpError
// @Failure 500 {object} common.HttpError
// @Router /users [post]
// @Security JWT
func (u *userController) Create(c *gin.Context) {
var createUserDto user.CreateUserDto
if err := c.BindJSON(&createUserDto); err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

user, err := u.UserService.Create(&createUserDto)
if err != nil {
utils.RaiseHttpError(c, http.StatusInternalServerError, err)
common.RaiseHttpError(c, http.StatusInternalServerError, err)
return
}

Expand All @@ -108,16 +107,16 @@ func (u *userController) Create(c *gin.Context) {
// @Summary Get my profile
// @Tags users
// @Success 200 {object} model.User
// @Failure 400 {object} utils.HttpError
// @Failure 500 {object} utils.HttpError
// @Failure 400 {object} common.HttpError
// @Failure 500 {object} common.HttpError
// @Router /users/me [post]
// @Security JWT
func (u *userController) Me(c *gin.Context) {
id, _ := c.Get("user")

user, err := u.UserService.FindById(uint(id.(int)))
if err != nil {
utils.RaiseHttpError(c, http.StatusNotFound, err)
common.RaiseHttpError(c, http.StatusNotFound, err)
return
}

Expand All @@ -130,32 +129,32 @@ func (u *userController) Me(c *gin.Context) {
// @Param id path integer true "User ID"
// @Param request body user.UpdateUserDto true "UpdateUserDto"
// @Success 200 {object} model.User
// @Failure 400 {object} utils.HttpError
// @Failure 404 {object} utils.HttpError
// @Failure 500 {object} utils.HttpError
// @Failure 400 {object} common.HttpError
// @Failure 404 {object} common.HttpError
// @Failure 500 {object} common.HttpError
// @Router /users/{id} [patch]
// @Security JWT
func (u *userController) Update(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

if _, err := u.UserService.FindById(uint(id)); err != nil {
utils.RaiseHttpError(c, http.StatusNotFound, err)
common.RaiseHttpError(c, http.StatusNotFound, err)
return
}

var updateUserDto user.UpdateUserDto
if err := c.BindJSON(&updateUserDto); err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

user, err := u.UserService.Update(&updateUserDto, uint(id))
if err != nil {
utils.RaiseHttpError(c, http.StatusInternalServerError, err)
common.RaiseHttpError(c, http.StatusInternalServerError, err)
return
}

Expand All @@ -169,18 +168,18 @@ func (u *userController) Update(c *gin.Context) {
// @Tags users
// @Param id path integer true "User ID"
// @Success 200
// @Failure 500 {object} utils.HttpError
// @Failure 500 {object} common.HttpError
// @Router /users/{id} [delete]
// @Security JWT
func (u *userController) Delete(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
utils.RaiseHttpError(c, http.StatusBadRequest, err)
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}

if err := u.UserService.Delete(uint(id)); err != nil {
utils.RaiseHttpError(c, http.StatusInternalServerError, err)
common.RaiseHttpError(c, http.StatusInternalServerError, err)
return
}

Expand Down
Loading

0 comments on commit cb106d7

Please sign in to comment.