Gin error handler that responds with proper error responses when an error is added to the context. https://pkg.go.dev/codeberg.org/danjones000/gin-error-handler
Find a file
2024-02-07 09:19:14 -06:00
.gitignore 🎉 Initial commit 2024-01-17 21:25:44 -06:00
CHANGELOG.md 📝 Update CHANGELOG 2024-02-07 09:18:44 -06:00
go.mod ⬆️ Upgrade responsable-errors 2024-02-07 09:15:04 -06:00
go.sum ⬆️ Upgrade responsable-errors 2024-02-07 09:15:04 -06:00
handler.go 🐛 Abort after error 2024-02-07 08:41:54 -06:00
handler_test.go Add HandlerWithError 2024-01-17 23:17:21 -06:00
int_test.go 🧪 Add integration test 2024-02-07 08:40:26 -06:00
LICENSE 🎉 Initial commit 2024-01-17 21:25:44 -06:00
middleware.go 🐛 Only send response if not already sent 2024-02-07 08:49:09 -06:00
middleware_test.go 🔊 Add WithLogger so we can log the rendered error 2024-01-22 10:29:58 -06:00
options.go 📝 Add godocs 2024-01-22 20:08:03 -06:00
options_test.go Add options, mostly transformers 2024-01-21 21:40:06 -06:00
README.md 📝 Better documentation. 2024-01-22 22:20:04 -06:00

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.