独自エラーを作成
独自のエラー構造体を作成し、業務処理でエラーが発生した際にハンドリングして json レスポンスを返す実装のサンプルです。
実装例
internal/apperrors
apperrors パッケージに下記要領で独自エラーを作成します:
base.go
独自エラーのインターフェースおよびエラーハンドリング向け関数を宣言します。各種独自例外はこのインターフェースを実装する形で作成し、HandleError 関数経由でレスポンスを作成します。
package apperrors
import "net/http"
// エラーのインターフェースです。
type EasyappError interface {
// エラーメッセージを管理します。
Error() string
// エラー向けのレスポンスモデルを作成します。
ReturnError(w http.ResponseWriter)
}
// エラーのハンドリングを行います。
// EasyappErrorを実装したエラーであればそのハンドリング処理を呼び出し、それ以外は500エラーを返します。
func HandleError(w http.ResponseWriter, err error) {
if e, ok := err.(EasyappError); ok {
e.ReturnError(w)
return
}
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
sample_error.go
独自エラーの実装です。ReturnError でレスポンスモデルの作成処理を行っています。
package apperrors
import (
"encoding/json"
"net/http"
)
// サンプルのエラーです。
type SampleError struct {
message string // エラーメッセージ
}
func NewSampleError(message string) EasyappError {
return &SampleError{message: message}
}
func (e *SampleError) Error() string {
return e.message
}
func (e *SampleError) ReturnError(w http.ResponseWriter) {
res := sampleErrorRes{Message: e.message}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(res)
}
// サンプルエラーのレスポンスモデルです。
type sampleErrorRes struct {
Message string `json:"message"` // エラーメッセージ
}
internal/usecase
usecase パッケージにて、下記要領でエラーを handler に返します:
auth_usecase.go
package usecase
import (
"easyapp/internal/apperrors"
"easyapp/internal/domain"
"easyapp/internal/usecase/payload"
)
// 認証の業務処理インターフェースです。
type AuthUsecase interface {
// 認証処理を行います。
Login(in payload.LoginIn) (payload.LoginOut, error)
}
type authUsecase struct {
authRepository domain.UsersRepository
}
func NewAuthUsecase(authRepository domain.UsersRepository) AuthUsecase {
return &authUsecase{authRepository: authRepository}
}
func (u *authUsecase) Login(in payload.LoginIn) (payload.LoginOut, error) {
user, err := u.authRepository.FindByName(in.Name())
if err != nil { // repositoryでエラーが発生したらEasyappErrorを戻す
return payload.NewLoginOut(false), apperrors.NewSampleError(err.Error())
}
return payload.NewLoginOut(user.Password() == in.Password()), nil
}
internal/handler
handler パッケージにて、下記要領でエラーハンドリングを行います:
auth_handler.go
package handler
import (
"easyapp/internal/apperrors"
"easyapp/internal/handler/model"
"easyapp/internal/usecase"
"easyapp/internal/usecase/payload"
"encoding/json"
"net/http"
)
// 認証のハンドラインターフェースです。
type AuthHandler interface {
// 認証処理を呼び出します。
Login(w http.ResponseWriter, r *http.Request)
}
type authHandler struct {
authUsecase usecase.AuthUsecase
}
func NewAuthHandler(authUsecase usecase.AuthUsecase) AuthHandler {
return &authHandler{authUsecase: authUsecase}
}
func (h *authHandler) Login(w http.ResponseWriter, r *http.Request) {
req := model.NewLoginReq(r)
out, err := h.authUsecase.Login(payload.NewLoginIn(req.Name, req.Password))
if err != nil { // EasyappErrorが返ってきたらハンドリング
apperrors.HandleError(w, err)
return
}
res := model.NewLoginRes(out.Valid())
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(res)
}