Golangでログイン機能を実装する。(Step3:Validationチェックの結果に応じて、レスポンスを変更する。)

### はじめに
[前回記事](https://qiita.com/kouji0705/items/daebf3d721d86ee54868)の続きです。
前回までにオウム返しのAPIを作成しました。今回はリクエスト内容のValidationを実施し、レスポンスを変更するAPIを作成します。

### 成果物
リクエスト成功
![スクリーンショット 2022-08-11 15.20.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/cba06c87-555e-33be-6d1f-a681d7f6b1a3.png)

リクエスト失敗
![スクリーンショット 2022-08-11 15.20.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/6bae0fbe-e106-ebda-d04a-c7a2bae15343.png)

### Hands-on
```shell:ディレクトリ構成
~/go/src/fiber_login$ tree -I tmp 
.
├── controller
│   └── loginController.go
├── customError
│   ├── error.go
│   └── validationError.go
├── go.mod
├── go.sum
├── main.go
└── model
    └── user.go

3 directories, 7 files
```

```go:go.mod
module fiber_login

go 1.19

require github.com/gofiber/fiber/v2 v2.36.0

require (
	github.com/go-playground/locales v0.14.0 // indirect
	github.com/go-playground/universal-translator v0.18.0 // indirect
	github.com/leodido/go-urn v1.2.1 // indirect
	golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
	golang.org/x/text v0.3.7 // indirect
)

require (
	github.com/andybalholm/brotli v1.0.4 // indirect
	github.com/cosmtrek/air v1.40.4 // indirect
	github.com/creack/pty v1.1.18 // indirect
	github.com/fatih/color v1.13.0 // indirect
	github.com/fsnotify/fsnotify v1.5.4 // indirect
	github.com/go-playground/validator v9.31.0+incompatible
	github.com/go-playground/validator/v10 v10.11.0
	github.com/imdario/mergo v0.3.13 // indirect
	github.com/klauspost/compress v1.15.0 // indirect
	github.com/mattn/go-colorable v0.1.12 // indirect
	github.com/mattn/go-isatty v0.0.14 // indirect
	github.com/pelletier/go-toml v1.9.5 // indirect
	github.com/valyala/bytebufferpool v1.0.0 // indirect
	github.com/valyala/fasthttp v1.38.0 // indirect
	github.com/valyala/tcplisten v1.0.0 // indirect
	golang.org/x/sys v0.0.0-20220808155132-1c4a2a72c664 // indirect
)
```

```go:main.go
package main

import (
	"fiber_login/controller"
	"log"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
)

func main() {
	app := fiber.New()

	app.Use(cors.New())

	// POST /login
	app.Post("/api/login", controller.Login)

	log.Fatal(app.Listen(":1323"))
}
```

```go:controller/loginController.go
package controller

import (
	"fiber_login/customError"
	"fiber_login/model"

	"github.com/gofiber/fiber/v2"
)

func Login(c *fiber.Ctx) error{
	user := new(model.User)

	// Parse JSON body
	c.BodyParser(user); 

	// Validate user
	errors := customError.ValidateStruct(*user)

	if errors != nil {
       return c.Status(fiber.StatusBadRequest).JSON(errors)    
    }

	return c.Status(fiber.StatusOK).JSON(user)
}
```

```go:customError/error.go
package customError

type ErrorResponse struct {
    FailedField string
    Tag         string
    Value       string
}
```

```go:customError/validationError.go
package customError

import (
	"fiber_login/model"

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

var validate = validator.New()

func ValidateStruct(user model.User) []*ErrorResponse {
    var errors []*ErrorResponse
    err := validate.Struct(user)
    if err != nil {
        for _, err := range err.(validator.ValidationErrors) {
            var element ErrorResponse
            element.FailedField = err.StructNamespace()
            element.Tag = err.Tag()
            element.Value = err.Param()
            errors = append(errors, &element)
        }
    }
    return errors
}
```

```go:model/user.go
package model

type User struct {
	UserID   string `json:"user_id" validate:"required,min=5,max=32"`
	Password string `json:"password" validate:"required,min=5,max=32"`
}
```
→いい感じに完成！！！