独自エラーを作成
独自のエラー構造体を作成し、業務処理でエラーが発生した際にハンドリングして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に返します:
users_usecase.go
package usecase
import (
"easyapp/internal/apperrors"
"easyapp/internal/domain"
"easyapp/internal/usecase/params"
)
// 認証の業務処理インターフェースです。
type UsersUsecase interface {
// 認証処理を行います。
Login(in params.LoginIn) (params.LoginOut, error)
}
type usersUsecase struct {
usersRepository domain.UsersRepository
}
func NewUsersUsecase(usersRepository domain.UsersRepository) UsersUsecase {
return &usersUsecase{usersRepository: usersRepository}
}
func (u *usersUsecase) Login(in params.LoginIn) (params.LoginOut, error) {
user, err := u.usersRepository.FindByName(in.Name())
if err != nil {
return params.NewLoginOut(false), apperrors.NewSampleError(err.Error())
}
return params.NewLoginOut(user.Password() == in.Password()), nil
}
internal/handler
handlerパッケージにて、下記要領でエラーハンドリングを行います:
users_handler.go
package handler
import (
"easyapp/internal/apperrors"
"easyapp/internal/handler/model"
"easyapp/internal/usecase"
"easyapp/internal/usecase/params"
"encoding/json"
"net/http"
)
// 認証のハンドラインターフェースです。
type UsersHandler interface {
// 認証処理を呼び出します。
Login(w http.ResponseWriter, r *http.Request)
}
type usersHandler struct {
usersUsecase usecase.UsersUsecase
}
func NewUsersHandler(usersUsecase usecase.UsersUsecase) UsersHandler {
return &usersHandler{usersUsecase: usersUsecase}
}
func (h *usersHandler) Login(w http.ResponseWriter, r *http.Request) {
req := model.NewLoginReq(r)
out, err := h.usersUsecase.Login(params.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)
}