mirror of
https://github.com/kataras/iris.git
synced 2025-12-18 18:37:05 +00:00
Add new x/errors/validation package to make your life even more easier (using Generics)
This commit is contained in:
@@ -1,119 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/x/errors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := newApp()
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
app.Get("/", fireCustomValidationError)
|
||||
app.Get("/multi", fireCustomValidationErrors)
|
||||
app.Get("/invalid", fireInvalidError)
|
||||
return app
|
||||
}
|
||||
|
||||
type MyValidationError struct {
|
||||
Field string `json:"field"`
|
||||
Value interface{} `json:"value"`
|
||||
Reason string `json:"reason"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func (err MyValidationError) Error() string {
|
||||
return fmt.Sprintf("field %q got invalid value of %v: reason: %s", err.Field, err.Value, err.Reason)
|
||||
}
|
||||
|
||||
// Error, GetField, GetValue and GetReason completes
|
||||
// the x/errors.ValidationError interface which can be used
|
||||
// for faster rendering without the necessity of registering a custom
|
||||
// type (see at the end of the example).
|
||||
//
|
||||
// func (err MyValidationError) GetField() string {
|
||||
// return err.Field
|
||||
// }
|
||||
//
|
||||
// func (err MyValidationError) GetValue() interface{} {
|
||||
// return err.Value
|
||||
// }
|
||||
//
|
||||
// func (err MyValidationError) GetReason() string {
|
||||
// return err.Reason
|
||||
// }
|
||||
|
||||
const shouldFail = true
|
||||
|
||||
func fireCustomValidationError(ctx iris.Context) {
|
||||
if shouldFail {
|
||||
err := MyValidationError{
|
||||
Field: "username",
|
||||
Value: "",
|
||||
Reason: "empty string",
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
|
||||
// The "validation" field, when used, is always rendering as
|
||||
// a JSON array, NOT a single object.
|
||||
errors.InvalidArgument.Err(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.WriteString("OK")
|
||||
}
|
||||
|
||||
// Optionally register custom types that you may need
|
||||
// to be rendered as validation errors if the given "ErrorCodeName.Err.err"
|
||||
// input parameter is matched with one of these. Register once, at initialiation.
|
||||
func init() {
|
||||
mapper := errors.NewValidationErrorTypeMapper(MyValidationError{} /*, OtherCustomType{} */)
|
||||
errors.RegisterValidationErrorMapper(mapper)
|
||||
}
|
||||
|
||||
// A custom type of the example validation error type
|
||||
// in order to complete the error interface, so it can be
|
||||
// pass through the errors.InvalidArgument.Err method.
|
||||
type MyValidationErrors []MyValidationError
|
||||
|
||||
func (m MyValidationErrors) Error() string {
|
||||
return "to be an error"
|
||||
}
|
||||
|
||||
func fireCustomValidationErrors(ctx iris.Context) {
|
||||
if shouldFail {
|
||||
errs := MyValidationErrors{
|
||||
{
|
||||
Field: "username",
|
||||
Value: "",
|
||||
Reason: "empty string",
|
||||
Timestamp: time.Now().Unix(),
|
||||
},
|
||||
{
|
||||
Field: "birth_date",
|
||||
Value: "2022-01-01",
|
||||
Reason: "too young",
|
||||
Timestamp: time.Now().Unix(),
|
||||
},
|
||||
}
|
||||
errors.InvalidArgument.Err(ctx, errs)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.WriteString("OK")
|
||||
}
|
||||
|
||||
func fireInvalidError(ctx iris.Context) {
|
||||
if shouldFail {
|
||||
errors.InvalidArgument.Err(ctx, fmt.Errorf("just a custom error text"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.WriteString("OK")
|
||||
}
|
||||
@@ -6,12 +6,13 @@ import (
|
||||
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/x/errors"
|
||||
"github.com/kataras/iris/v12/x/errors/validation"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
|
||||
service := new(myService)
|
||||
|
||||
app.Post("/", createHandler(service))
|
||||
app.Get("/", listHandler(service))
|
||||
app.Delete("/{id:string}", deleteHandler(service))
|
||||
@@ -70,16 +71,65 @@ type (
|
||||
myService struct{}
|
||||
|
||||
CreateRequest struct {
|
||||
Fullname string
|
||||
Fullname string `json:"fullname"`
|
||||
Age int `json:"age"`
|
||||
Hobbies []string `json:"hobbies"`
|
||||
}
|
||||
|
||||
CreateResponse struct {
|
||||
ID string
|
||||
Firstname string
|
||||
Lastname string
|
||||
ID string `json:"id"`
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
Age int `json:"age"`
|
||||
Hobbies []string `json:"hobbies"`
|
||||
}
|
||||
)
|
||||
|
||||
// ValidateContext implements the errors.ContextValidator interface.
|
||||
// It validates the request body and returns an error if the request body is invalid.
|
||||
// You can also alter the "r" CreateRequest before calling the service method,
|
||||
// e.g. give a default value to a field if it's empty or set an ID based on a path parameter.
|
||||
func (r *CreateRequest) ValidateContext(ctx iris.Context) error {
|
||||
// To pass custom validation functions:
|
||||
// return validation.Join(
|
||||
// validation.String("fullname", r.Fullname).Func(customStringFuncHere),
|
||||
// OR
|
||||
// validation.Field("any_field", r.AnyFieldValue).Func(customAnyFuncHere))
|
||||
return validation.Join(
|
||||
validation.String("fullname", r.Fullname).NotEmpty().Fullname().Length(3, 50),
|
||||
validation.Number("age", r.Age).InRange(18, 130),
|
||||
validation.Slice("hobbies", r.Hobbies).Length(1, 10),
|
||||
)
|
||||
|
||||
/* Example Output:
|
||||
{
|
||||
"http_error_code": {
|
||||
"canonical_name": "INVALID_ARGUMENT",
|
||||
"status": 400
|
||||
},
|
||||
"message": "validation failure",
|
||||
"details": "fields were invalid",
|
||||
"validation": [
|
||||
{
|
||||
"field": "fullname",
|
||||
"value": "",
|
||||
"reason": "must not be empty, must contain first and last name, must be between 3 and 50 characters"
|
||||
},
|
||||
{
|
||||
"field": "age",
|
||||
"value": 0,
|
||||
"reason": "must be in range of [18, 130]"
|
||||
},
|
||||
{
|
||||
"field": "hobbies",
|
||||
"value": null,
|
||||
"reason": "must be between 1 and 10 elements"
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
func (s *myService) Create(ctx context.Context, in CreateRequest) (CreateResponse, error) {
|
||||
arr := strings.Split(in.Fullname, " ")
|
||||
firstname, lastname := arr[0], arr[1]
|
||||
@@ -89,6 +139,8 @@ func (s *myService) Create(ctx context.Context, in CreateRequest) (CreateRespons
|
||||
ID: id,
|
||||
Firstname: firstname,
|
||||
Lastname: lastname,
|
||||
Age: in.Age,
|
||||
Hobbies: in.Hobbies,
|
||||
}
|
||||
return resp, nil // , errors.New("create: test error")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user