🙅‍♀️

【Golang】カスタムエラー 前編

2022/07/27に公開

最近某pomeさんにありがたいコードレビューをいただいているので復習と発信のために残します
logに関するお話は後編で

Goのエラーライブラリについて

  • Go言語は、関数やメソッドの戻り値としてerrorインターフェースを実装したオブジェクトをreturnすることで、エラーの発生を呼び出し元に伝える仕組み。
  • 呼び出しもとでは、そのエラーをされにreturnすることによって、呼び出しもとを辿ってエラーをreturnする。最終的にプログラムが実行された場所まで戻ることが可能。

pkg/errorsはスタックトレース機能付き

  • errorパッケージは単体でもできるが、スタックトレース機能が付いてない。
    pkg/errorsを利用するとスタックトレースが出力できる。

でも限界がある

まず、ログとして出力するエラーの種類には以下がある

  • ログレベル
  • ユーザーID
  • エラーが発生した時刻(ログの出力時刻)
  • エラーコード
  • エラーメッセージ
  • スタックトレース
  • クライアントがHTTPリクエストをリトライできるかどうか
  • 特定のページにリダイレクトが必要かどうか

上記のようにさまざまな情報をログとして出力するが、plg/errorで全て扱えるわけではないので、カスタムエラーを自作する手もある。

カスタムエラーについて

errorが発生した箇所でreasonやstatuscode渡し、

//error用のpayload的なものを作ってる
//codeをdetailに変換
type Kind string
type Code struct {
	Kind Kind
	Code string
	MessageForEndUser string
}
func NewMessage(c Code, format string, val ...interface{}) Detail {
	return Detail{
		code:                c,
		messageForDeveloper: fmt.Sprintf(format, val...),
	}
}


//引数に上のNewMessageを入れるとerror型で返せる
//detailをerrorに変換
type Error struct {
	details []Detail
	err     error
	frames  *runtime.Frames
}

//stringを返すErrorというメソッドを実装している(★)
//→エラーインターフェースを実装している
func (e *Error) Error() string {
	//ちょめちょめ
}
type Detail struct {
	code                Code
	messageForDeveloper string
}
func NewError(m ...Detail) error {
	return newError(nil, m...)
}
func newError(err error, m ...Detail) error {
	return &Error{
		details: m,
		err:     err,
		frames:  newFrames(),
	}
}

ちなみにエラーインターフェースはこちら

type error interface {
	Error() string
}

使う時

//NewErrorの第一引数がcodeで、そのkeyを渡すことでkindもcodeもmessageも渡せてる
apperror.NewError(apperror.NewMessage(apperror.CodeNotFound, “ss”))

★の部分にもあるとおり、stringを返すError()メソッドを実装(エラーインターフェース)を実装してれば、戻りその構造体はerror型にできる。

Discussion