Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

커스텀 에러를 error 미들웨어에서 처리합니다. #101

Merged
merged 2 commits into from
Dec 22, 2024

Conversation

litsynp
Copy link
Contributor

@litsynp litsynp commented Dec 22, 2024

기존 방식의 단점

  • 서비스 함수의 시그니처가 항상 error 대신 *pnd.AppError로 강제되어 비즈니스 로직과 별개로 존재하는 함수도 래핑해서 생성해야 했음.
  • 호환되지 않는 두 타입 error*pnd.AppError가 혼재하여 err 외에도 err2, err3을 써야하는 경우가 많았음.
  • AppError가 나가는 방식은 항상 c.JSON(appErr.code, appErr.response)로 동일한데 매번 명시해줘야 했음.
  • DB 에러 발생 시 FromPostgresError를 까먹고 안하면 문제 발생.

해결 방안

  • pnd.AppErrorerror 인터페이스를 구현합니다.
  • router.go에 에러 미들웨어를 추가해 AppError, FromPostgresError를 한 곳에서 처리합니다.
  • 기존 서비스 코드에서 Error를 발생하는 함수에는 error을 반환하도록 하고, 에러 유틸을 이용해 응답을 만듭니다.
  • 기존 코드에서 DB 에러 발생 시 FromPostgresError 래핑하는 부분 일괄 제거합니다.

앞으로의 방안

앞으로 이렇게 서비스 함수를 작성하면 됩니다.

  1. 함수에서 error가 발생한다면 정의 부분에선 항상 error 타입으로 넣어줍니다.
  2. DB 에러 발생시에는 그냥 return err 해주면 됩니다. (FromPostgresError는 직접 호출하지 않습니다.)
  3. 이외의 에러는 기존처럼 에러 응답을 만들 땐 에러 유틸 코드를 이용해 응답을 만들어 반환합니다.
  4. 서비스에서 AppError를 만들었다면 핸들러에서 에러 응답을 가공하지 않아도 됩니다. 그냥 err을 리턴해버리면 됩니다.
// 예시로 만든 코드
func (s *PetService) CheckPermission(owner User, pet Pet) error {
	// ...

	if petToUpdate.OwnerID != owner.ID {
		return pnd.ErrForbidden(errors.New("해당 반려동물을 수정할 권한이 없습니다"))
	}

	// ...

	return nil
}

@litsynp litsynp added chore Miscellaneous stuff refactor Outer changes to codes labels Dec 22, 2024
@litsynp litsynp requested a review from JoeCP17 December 22, 2024 03:35
@litsynp litsynp self-assigned this Dec 22, 2024
Comment on lines +49 to +52
func (e *AppError) Error() string {
return e.Message
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error 인터페이스 구현해서 AppError 타입이 error로 반환될 수 있도록 합니다.

Comment on lines +96 to +118
// Error handler
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
err := next(c)
if err != nil {
var appErr *pnd.AppError
if errors.As(err, &appErr) {
return c.JSON(appErr.StatusCode, appErr)
}

if err := pnd.FromPostgresError(err); err != nil {
if errors.As(err, &appErr) {
return c.JSON(appErr.StatusCode, appErr)
}
}

return c.JSON(http.StatusInternalServerError, pnd.ErrUnknown(err))
}

return err
}
})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

새로 추가된 에러 미들웨어입니다. 에러를 응답으로 만들어주는 부분은 여기서 진행되어 이제 핸들러에서 하지 않아도 됩니다.

Copy link
Contributor

@JoeCP17 JoeCP17 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확실히 이전보다 에러 핸들링할떄 관리포인트가 줄어들어 관리하기 편할것 같네요

수고하셨습니다!

@litsynp
Copy link
Contributor Author

litsynp commented Dec 22, 2024

🙇

@litsynp litsynp merged commit 9ea0416 into main Dec 22, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chore Miscellaneous stuff refactor Outer changes to codes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants