├── .gitignore ├── static ├── style.css ├── index.html └── app.js ├── README.md ├── go.mod ├── main.go └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | go-ozzo-validation-example 2 | *.exe 3 | -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | #message { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-ozzo-validation-example 2 | 3 | Example app using labstack/echo and ozzo-validator. 4 | 5 | ## Build 6 | 7 | ``` 8 | $ go build 9 | $ ./go-ozzo-validation-example 10 | ``` 11 | 12 | ## License 13 | 14 | MIT 15 | 16 | ## Author 17 | 18 | Yasuhiro Matsumoto (a.k.a. mattn) 19 | -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | example 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/mattn/go-ozzo-validation-example 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/go-ozzo/ozzo-validation/v4 v4.3.0 7 | github.com/labstack/echo/v4 v4.11.4 8 | ) 9 | 10 | require ( 11 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect 12 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect 13 | github.com/labstack/gommon v0.4.2 // indirect 14 | github.com/mattn/go-colorable v0.1.13 // indirect 15 | github.com/mattn/go-isatty v0.0.20 // indirect 16 | github.com/valyala/bytebufferpool v1.0.0 // indirect 17 | github.com/valyala/fasttemplate v1.2.2 // indirect 18 | golang.org/x/crypto v0.17.0 // indirect 19 | golang.org/x/net v0.19.0 // indirect 20 | golang.org/x/sys v0.15.0 // indirect 21 | golang.org/x/text v0.14.0 // indirect 22 | golang.org/x/time v0.5.0 // indirect 23 | ) 24 | -------------------------------------------------------------------------------- /static/app.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('DOMContentLoaded', () => { 2 | document.querySelector('#submit').addEventListener('click', () => { 3 | axios.post('/api', { 4 | name: document.querySelector('#name').value, 5 | email: document.querySelector('#email').value, 6 | content: document.querySelector('#content').value, 7 | }, { 8 | headers: {'Content-Type': 'application/json'}, 9 | responseType: 'json', 10 | }) 11 | .then((response) => { 12 | document.querySelector('#message').textContent = ''; 13 | document.querySelector('#name').value = ''; 14 | document.querySelector('#email').value = ''; 15 | document.querySelector('#content').value = ''; 16 | }) 17 | .catch((error) => { 18 | document.querySelector('#message').textContent = error.response.data.error; 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "embed" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "regexp" 9 | "strings" 10 | 11 | validation "github.com/go-ozzo/ozzo-validation/v4" 12 | "github.com/go-ozzo/ozzo-validation/v4/is" 13 | "github.com/labstack/echo/v4" 14 | "github.com/labstack/echo/v4/middleware" 15 | ) 16 | 17 | type Comment struct { 18 | Name string `json:"name"` 19 | Email string `json:"email"` 20 | Content string `json:"content"` 21 | } 22 | 23 | type CustomValidator struct{} 24 | 25 | func (cv *CustomValidator) Validate(i interface{}) error { 26 | if c, ok := i.(validation.Validatable); ok { 27 | return c.Validate() 28 | } 29 | return nil 30 | } 31 | 32 | func (a Comment) Validate() error { 33 | return validation.ValidateStruct(&a, 34 | validation.Field( 35 | &a.Name, 36 | validation.Required.Error("名前は必須入力です"), 37 | validation.RuneLength(5, 20).Error("名前は {min}~{max} 文字です"), 38 | is.PrintableASCII.Error("名前はASCIIで入力して下さい"), 39 | ), 40 | validation.Field( 41 | &a.Email, 42 | validation.Required.Error("メールアドレスは必須入力です"), 43 | validation.RuneLength(5, 40).Error("メールアドレスは {min}~{max} 文字です"), 44 | is.Email.Error("メールアドレスを入力して下さい"), 45 | ), 46 | validation.Field( 47 | &a.Content, 48 | validation.Required.Error("本文は必須入力です"), 49 | validation.RuneLength(5, 50).Error("本文は {min}~{max} 文字です"), 50 | ), 51 | ) 52 | } 53 | 54 | //go:embed static 55 | var localFS embed.FS 56 | 57 | func main() { 58 | e := echo.New() 59 | e.Debug = true 60 | e.Validator = &CustomValidator{} 61 | e.Use(middleware.Logger()) 62 | e.Use(middleware.StaticWithConfig(middleware.StaticConfig{ 63 | Root: "static", 64 | Filesystem: http.FS(localFS), 65 | })) 66 | 67 | e.POST("/api", func(c echo.Context) error { 68 | var comment Comment 69 | if err := c.Bind(&comment); err != nil { 70 | return err 71 | } 72 | if err := c.Validate(comment); err != nil { 73 | errs := err.(validation.Errors) 74 | re := regexp.MustCompile(`{[a-z]+}`) 75 | for k, err := range errs { 76 | c.Logger().Error(k + ": " + err.Error()) 77 | verr := err.(validation.Error) 78 | params := verr.Params() 79 | errs[k] = errors.New(re.ReplaceAllStringFunc(verr.Message(), func(s string) string { 80 | return fmt.Sprint(params[strings.Trim(s, "{}")]) 81 | })) 82 | } 83 | return errs 84 | } 85 | return c.JSON(http.StatusOK, &struct { 86 | Result string `json:"result"` 87 | }{ 88 | Result: "OK", 89 | }) 90 | }) 91 | e.Logger.Fatal(e.Start(":8989")) 92 | } 93 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= 2 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= 3 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 6 | github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es= 7 | github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew= 8 | github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= 9 | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 10 | github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= 11 | github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= 12 | github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= 13 | github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= 14 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 15 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 16 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 17 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 18 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 19 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 20 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 21 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 22 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 23 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 24 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 25 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 26 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= 27 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 28 | golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= 29 | golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 30 | golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= 31 | golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= 32 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 33 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 34 | golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= 35 | golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 36 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 37 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 38 | golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= 39 | golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 40 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 41 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 42 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 43 | --------------------------------------------------------------------------------