-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc(fxvalidator): Provided module documentation (#308)
- Loading branch information
Showing
3 changed files
with
383 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,382 @@ | ||
--- | ||
title: Modules - Log | ||
icon: material/cube-outline | ||
--- | ||
|
||
# :material-cube-outline: Validator Module | ||
|
||
[![ci](https://github.com/ankorstore/yokai/actions/workflows/fxvalidator-ci.yml/badge.svg)](https://github.com/ankorstore/yokai/actions/workflows/fxvalidator-ci.yml) | ||
[![go report](https://goreportcard.com/badge/github.com/ankorstore/yokai/fxvalidator)](https://goreportcard.com/report/github.com/ankorstore/yokai/fxvalidator) | ||
[![codecov](https://codecov.io/gh/ankorstore/yokai/graph/badge.svg?token=ghUBlFsjhR&flag=fxvalidator)](https://app.codecov.io/gh/ankorstore/yokai/tree/main/fxvalidator) | ||
[![Deps](https://img.shields.io/badge/osi-deps-blue)](https://deps.dev/go/github.com%2Fankorstore%2Fyokai%2Ffxvalidator) | ||
[![PkgGoDev](https://pkg.go.dev/badge/github.com/ankorstore/yokai/fxvalidator)](https://pkg.go.dev/github.com/ankorstore/yokai/fxvalidator) | ||
## Overview | ||
|
||
Yokai provides a [fxvalidator](https://github.com/ankorstore/yokai/tree/main/fxvalidator) module, allowing you to inject a validator anywhere needed. | ||
|
||
It wraps the [go-playground/validator](https://github.com/go-playground/validator) module. | ||
|
||
## Installation | ||
|
||
First install the module: | ||
|
||
```shell | ||
go get github.com/ankorstore/yokai/fxvalidator | ||
``` | ||
|
||
Then activate it in your application bootstrapper: | ||
|
||
```go title="internal/bootstrap.go" | ||
package internal | ||
|
||
import ( | ||
"github.com/ankorstore/yokai/fxcore" | ||
"github.com/ankorstore/yokai/fxvalidator" | ||
) | ||
|
||
var Bootstrapper = fxcore.NewBootstrapper().WithOptions( | ||
// modules registration | ||
fxvalidator.FXValidatorModule, | ||
// ... | ||
) | ||
``` | ||
|
||
## Configuration | ||
|
||
Configuration reference: | ||
|
||
```yaml title="configs/config.yaml" | ||
modules: | ||
validator: | ||
tag_name: validate # struct tag to define validation rules, default = validate | ||
private_fields: false # to enable validation on private fields, disabled by default | ||
``` | ||
## Usage | ||
This module makes available a `*validator.Validate` instance in | ||
Yokai dependency injection system, that you can inject anywhere. | ||
|
||
For example: | ||
|
||
```go title="internal/service/example.go" | ||
package service | ||
import ( | ||
"fmt" | ||
"github.com/go-playground/validator/v10" | ||
) | ||
type ExampleStruct struct { | ||
Name string `validate:"required"` | ||
Email string `validate:"required,email"` | ||
} | ||
|
||
type ExampleService struct { | ||
validate *validator.Validate | ||
} | ||
|
||
func NewExampleService(validate *validator.Validate) *ExampleService { | ||
return &ExampleService{ | ||
validate: validate, | ||
} | ||
} | ||
|
||
func (s *ExampleService) DoSomething() error { | ||
es := ExampleStruct{ | ||
Name: "name", | ||
Email: "[email protected]", | ||
} | ||
err := s.validate.Struct(es) | ||
if valErrs, ok := err.(*validator.ValidationErrors); ok { | ||
fmt.Println(valErrs) | ||
} | ||
return valErrs | ||
} | ||
``` | ||
|
||
See [go-playground/validator](https://github.com/go-playground/validator) documentation for more details about available validation features. | ||
|
||
## Customization | ||
|
||
This module provides the possibility to easily customize your validator. | ||
|
||
### Custom aliases | ||
|
||
You can register custom validation aliases with `AsAlias()`: | ||
|
||
```go title="internal/register.go" | ||
package internal | ||
|
||
import ( | ||
"github.com/ankorstore/yokai/fxvalidator" | ||
"go.uber.org/fx" | ||
) | ||
|
||
func Register() fx.Option { | ||
return fx.Options( | ||
// register the rla alias: provided value must be required, alpha only and lowercase | ||
fxvalidator.AsAlias("rla", "required,alpha,lowercase"), | ||
// ... | ||
) | ||
} | ||
``` | ||
|
||
Then: | ||
|
||
```go title="internal/service/example.go" | ||
package service | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
type ExampleService struct { | ||
validate *validator.Validate | ||
} | ||
|
||
func NewExampleService(validate *validator.Validate) *ExampleService { | ||
return &ExampleService{ | ||
validate: validate, | ||
} | ||
} | ||
|
||
func (s *ExampleService) DoSomething(ctx context.Context) error { | ||
// valid | ||
err := s.validate.VarCtx(ctx, "valid", "rla") | ||
|
||
// invalid | ||
err = s.validate.VarCtx(ctx, "1234", "rla") | ||
|
||
return err | ||
} | ||
``` | ||
|
||
### Custom validations | ||
|
||
You can register custom validations functions with `AsValidation()`: | ||
|
||
```go title="internal/register.go" | ||
package internal | ||
|
||
import ( | ||
"github.com/ankorstore/yokai/fxvalidator" | ||
"go.uber.org/fx" | ||
) | ||
|
||
func Register() fx.Option { | ||
return fx.Options( | ||
// register the foobar validation: provided lowercased value must be "foo" or "bar" | ||
fxvalidator.AsValidation( | ||
"foobar", | ||
func(ctx context.Context, fl validator.FieldLevel) bool { | ||
s := strings.ToLower(fl.Field().String()) | ||
|
||
return s == "foo" || s == "bar" | ||
}, | ||
true, | ||
), | ||
// ... | ||
) | ||
} | ||
``` | ||
|
||
Then: | ||
|
||
```go title="internal/service/example.go" | ||
package service | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
type ExampleService struct { | ||
validate *validator.Validate | ||
} | ||
|
||
func NewExampleService(validate *validator.Validate) *ExampleService { | ||
return &ExampleService{ | ||
validate: validate, | ||
} | ||
} | ||
|
||
func (s *ExampleService) DoSomething(ctx context.Context) error { | ||
// valid | ||
err := s.validate.VarCtx(ctx, "FoO", "foobar") | ||
|
||
// invalid | ||
err = s.validate.VarCtx(ctx, "invalid", "foobar") | ||
|
||
return err | ||
} | ||
``` | ||
|
||
### Custom struct validations | ||
|
||
You can register custom struct validations functions with `AsStructValidation()`: | ||
|
||
```go title="internal/register.go" | ||
package internal | ||
|
||
import ( | ||
"github.com/ankorstore/yokai/fxvalidator" | ||
"github.com/foo/bar/internal/service" | ||
"go.uber.org/fx" | ||
) | ||
|
||
func Register() fx.Option { | ||
return fx.Options( | ||
// register a struct validation for the struct service.ExampleStruct{} | ||
fxvalidator.AsStructValidation( | ||
func(ctx context.Context, sl validator.StructLevel) { | ||
fb, ok := sl.Current().Interface().(service.ExampleStruct) | ||
if ok { | ||
if fb.Foo != "foo" { | ||
sl.ReportError(fb.Foo, "Foo", "Foo", "invalid-foo", "invalid foo") | ||
} | ||
if fb.Bar != "bar" { | ||
sl.ReportError(fb.Bar, "Bar", "Bar", "invalid-bar", "invalid bar") | ||
} | ||
} | ||
}, | ||
service.ExampleStruct{}, | ||
), | ||
// ... | ||
) | ||
} | ||
``` | ||
|
||
Then: | ||
|
||
```go title="internal/service/example.go" | ||
package service | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
type ExampleStruct struct { | ||
Foo string | ||
Bar string | ||
} | ||
|
||
type ExampleService struct { | ||
validate *validator.Validate | ||
} | ||
|
||
func NewExampleService(validate *validator.Validate) *ExampleService { | ||
return &ExampleService{ | ||
validate: validate, | ||
} | ||
} | ||
|
||
func (s *ExampleService) DoSomething(ctx context.Context) error { | ||
// valid | ||
err := s.validate.StructCtx(ctx, ExampleStruct{Foo: "foo", Bar: "bar"}) | ||
|
||
// invalid | ||
err = s.validate.StructCtx(ctx, ExampleStruct{Foo: "invalid", Bar: ""}) | ||
|
||
return err | ||
} | ||
``` | ||
|
||
### Custom types | ||
|
||
You can register custom types functions with `AsCustomType()`: | ||
|
||
```go title="internal/register.go" | ||
package internal | ||
|
||
import ( | ||
"reflect" | ||
|
||
"github.com/ankorstore/yokai/fxvalidator" | ||
"github.com/foo/bar/internal/service" | ||
"go.uber.org/fx" | ||
) | ||
|
||
func Register() fx.Option { | ||
return fx.Options( | ||
// register a custom type function for service.Foo{} and service.Bar{} | ||
fxvalidator.AsCustomType( | ||
func(field reflect.Value) interface{} { | ||
if f, ok := field.Interface().(service.Foo); ok { | ||
if f.Value != "foo" { | ||
return "" | ||
} | ||
|
||
return f.Value | ||
} | ||
|
||
if b, ok := field.Interface().(service.Bar); ok { | ||
if b.Value != "bar" { | ||
return "" | ||
} | ||
|
||
return b.Value | ||
} | ||
|
||
return "" | ||
}, | ||
service.Foo{}, | ||
service.Bar{}, | ||
), | ||
// ... | ||
) | ||
} | ||
``` | ||
|
||
Then: | ||
|
||
```go title="internal/service/example.go" | ||
package service | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
type Foo struct { | ||
Value string `validate:"required"` | ||
} | ||
|
||
type Bar struct { | ||
Value string `validate:"required"` | ||
} | ||
|
||
type ExampleStruct struct { | ||
Foo Foo | ||
Bar Bar | ||
} | ||
|
||
type ExampleService struct { | ||
validate *validator.Validate | ||
} | ||
|
||
func NewExampleService(validate *validator.Validate) *ExampleService { | ||
return &ExampleService{ | ||
validate: validate, | ||
} | ||
} | ||
|
||
func (s *ExampleService) DoSomething(ctx context.Context) error { | ||
// valid | ||
err := s.validate.StructCtx(ctx, ExampleStruct{Foo: Foo{Value: "foo"}, Bar: Bar{Value: "bar"}}) | ||
|
||
// invalid | ||
err = s.validate.StructCtx(ctx, ExampleStruct{Foo: Foo{Value: "invalid"}, Bar: Bar{Value: ""}}) | ||
|
||
return err | ||
} | ||
``` |
Oops, something went wrong.