Field validation
Hi, thank you for your project, it's exactly what i'm looking for some time :100: I'm also developing rest API using Go and Echo and we use OpenAPI to document ours apis. In my apis, i'm a huge fan & user of package go-playground/validator to validate data i received (like min string length , etc...). It will be awesome if you could support this in schema structure generation. What do you think ? Do you need help to do that ?
One thing that could be great would be to use the JSON-Schema tags that can be included in the openapi schema itself https://swagger.io/docs/specification/data-models/keywords/
Some libs already exist to use JSON Schemas like https://github.com/xeipuuv/gojsonschema so the work may not be too huge
I had a similar requirement and I was able to build a viable solution by generating an echo server using oapi-codegen, and then registering a custom validator that implements go-playground/validator as mentioned in the echo documentation.
This is how you could do it -
Add a custom validate tag in the swagger for the fields that require validation say
x-oapi-codegen-extra-tags:
validate: excluded_with_all
The models get generated with this custom tag
`json:"id,omitempty" validate:"excluded_with_all"`
@kolluria did you have to call echo_ctx.Validate(myStructPointer) manually for each handler?
@bofm Yeah. You have to manually invoke echo_ctx.Validate after binding the request body to the struct.
For instance,
func (s serverImplementation) SomeHandler(c echo.Context) error {
var body SomeJSONRequestBody
err := c.Bind(&body)
if err != nil {
return err
}
err = c.Validate(&body)
if err != nil {
return err
}
// Your business logic goes here
}
@kolluria thanks for the answer.
I just found a way to not have to (and not forget to) call Validate() in each handler with the strict server:
type StructValidator struct {
validator *validator.Validate
}
func (v StructValidator) Validate(i interface{}) error {
if err := v.validator.Struct(i); err != nil {
return err
}
return nil
}
func validateStructMiddeware(f api.StrictHandlerFunc, operationID string) api.StrictHandlerFunc {
return func(ctx echo.Context, i interface{}) (interface{}, error) {
if err := ctx.Validate(i); err != nil {
return nil, fmt.Errorf("%s failed to validate request body: %w", operationID, err)
}
return f(ctx, i)
}
}
func main() {
e := echo.New()
e.Validator = StructValidator{validator: v}
apiServer := api.NewStrictHandler(
api.NewServer(theStorage),
[]api.StrictMiddlewareFunc{
validateStructMiddeware,
},
)
api.RegisterHandlers(e, apiServer)
}
this does not seem to work for nested fields. has anyone had success with tagging a nested field
edit: using the dive tag solved the problem