traPtitech / traPortfolio

部員の活動紹介サービス traPortfolio

Home Page:https://portfolio.trap.jp

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

エラーをラップする仕組みが欲しい

ras0q opened this issue · comments

現状convertErrorなどを使って下位層の具体的なエラーを上位層の抽象的なエラーに変換してレスポンスのステータスコードを決定しているが、下位層のエラーの情報が消えてしまっているのでラップしてログに詳細を吐き出せるようにしたい

util/errorsとかに自前errorsパッケージを定義して↓みたいな感じに実装するとよさそう

package errors

import (
	"errors"
	"fmt"
)

// 各パッケージのエラーはErrorMessage型で定義する
type ErrorMessage string

type customError struct {
	message  ErrorMessage
	internal error
}

func New(message ErrorMessage) error {
	return &customError{
		message: message,
	}
}

func Wrap(message ErrorMessage, internal error) error {
	return &customError{
		message:  message,
		internal: internal,
	}
}

// 標準errorsパッケージをラップ
func Is(err, target error) bool {
	return errors.Is(err, target)
}

// Errorインターフェイスの実装
func (e *customError) Error() string {
	if e.internal != nil {
		return fmt.Sprintf("%s: %s", e.message, e.internal.Error())
	}

	return string(e.message)
}

// 標準errorsパッケージで比較できるようにIsメソッドを実装
// 子エラーは判定には使わないのでUnwrapは実装しなくてもよい
func (e *customError) Is(target error) bool {
	if t, ok := target.(*customError); ok {
		return e.message == t.message
	}

	return false
}
  • エラーの定義をerrors.NewのvarからErrorMessageのconstに変える
  • echo.NewHTTPErrorをするときに.SetInternalをしてエラーをログに残す

これerrors.Isで比較するとなるとErrorMessageとは別に各ErrorMessageに対してerrors.Newで変数を定義することになって微妙な気がしてきた

errors.Isを使うのではなくcustomErrorcustomError.messageをpublicにしてerrors.Asで判定してから(ここは型アサーションで十分かも)、messageの種類でswitchで十分かも