Skip to content

バリデーション実装

リクエストパラメータのバリデーションを実装します。

cf.

事前準備

  • validatorパッケージをインストールします:
shell
go get github.com/go-playground/validator/v10

実装

internal/validation

バリデータを実装します。NewValidationErrorにてバリデーションエラーからエラーメッセージを作成しerror型として返します。

  • validator.go
go
package validation

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

var Validate = validator.New()

type ValidationError struct {
	Messages []string
}

func (e ValidationError) Error() string {
	return fmt.Sprintf("%v", e.Messages)
}

func NewValidationError(err error) ValidationError {
	validationErrors, ok := err.(validator.ValidationErrors)
	if !ok {
		return ValidationError{[]string{"unknown error"}}
	}
	var errorMessages []string
	for _, e := range validationErrors {
		errorMessages = append(
			errorMessages,
			fmt.Sprintf("invalid parameter. field: %s, tag: %s, value: %v",
				e.Field(),
				e.Tag(),
				e.Value(),
			),
		)
	}

	return ValidationError{Messages: errorMessages}
}

internal/presentation/handler/model

validateタグを用いてバリデーションを宣言し、validation.Validate.Structで値の検証を行います。

  • user_model.go
go
type LoginRequest struct {
	Name     string `json:"name"`                         // ユーザ名
	Password string `json:"password" validate:"required"` // パスワード
}

func NewLoginRequest(r *http.Request) (LoginRequest, error) {

	var req LoginRequest
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(&req); err != nil {
		return LoginRequest{}, err
	}

	if err := validation.Validate.Struct(req); err != nil {
		return LoginRequest{}, validation.NewValidationError(err)
	}

	return req, nil
}

internal/presentation/handler

NewLoginRequestからバリデーションエラーが返ってきた場合、そのエラーをAPIレスポンスとして返します。

  • user_handler.go
go
	req, err := model.NewLoginRequest(r)
	if err != nil {
		if err, ok := err.(validation.ValidationError); ok {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusUnprocessableEntity)
			json.NewEncoder(w).Encode(err)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusBadRequest)
		json.NewEncoder(w).Encode(
			struct {
				Message string `json:"message"`
			}{
				Message: "bad request",
			},
		)
		return
	}