gin-error-handler/README.md
Dan Jones 097419f5ef 📝 Better documentation.
Also a Changelog.
2024-01-22 22:20:04 -06:00

2.2 KiB

Gin Error Handler

A Gin middleware and wrapper functions to make handling errors easier.

Installation

Use the module in the usual way: codeberg.org/danjones000/gin-error-handler.

Usage

package main

import (
    "net/http"
    handler "codeberg.org/danjones000/gin-error-handler"
    rErrors "codeberg.org/danjones000/responsable-errors"
    "github.com/go-playground/validator/v10"
    "github.com/gin-gonic/gin"
)

var _ rErrors.ResponsableError = new(vError)

type vError struct {
    validator.ValidationErrors
}

func (ve *vError) Msg() string {
    return "Validation Error"
}

func (ve *vError) Status() int {
    return http.StatusBadRequest
}

func (ve *vError) JSON() any {
    errs := make([]map[string]string, len(ve))
    for i, fe := range ve {
        errs[i] = map[string]string{"field":fe.Field(),"error":fe.Error()}
    }
    return map[string][]map[string]string{"errors":errs}
}

func (ve *vError) MarshalJSON() ([]byte, error) {
	return json.Marshal(e.JSON())
}

func (ve *vError) Unwrap() error {
	return ve.ValidationErrors
}

func main() {
    r := gin.New()
    r.Use(handler.ErrorMiddleware(
        handler.WithTransformer(func (err error) rErrors.ResponsableError {
            var ve validator.ValidationErrors
            if !errors.As(err, &ve) {
                return nil
            }
            return &vError{ve}
        }),
        handler.WithDefaultTransformer(),
        handler.WithLogger(ctx context.Context, err rErrors.ResponsableError) {
            log.Print(err)
        })

    r.GET("/user", handler.HandlerWithErrorWrapper(func (c *gin.Context) error {
        var qu struct {
            id int `binding:"required"`
        }{}
        if err := c.ShouldBindQuery(&qu); err != nil {
            return err
        }
        user, err := user.Get(qu.id)
        if err != nil {
            return err
        }
        if user == nil {
            return rErrors.NewNotFound("User not found")
        }

        c.JSON(200, user)
    }))
}

In our example, if ShouldBindQuery fails validation, we'll return a nicely formatted error with each validation error, due to our custom transformer. If no user is found, we'll return a 404, with an error message. And any errors are logged to stdout.