87 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			87 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # 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
 | |
| 
 | |
| ```go
 | |
| 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.
 |