feat: custom recovery middleware

This commit is contained in:
Daniel G. Taylor 2020-03-30 21:47:38 -07:00
parent 5b12909537
commit 92422ae10d
No known key found for this signature in database
GPG key ID: 7BD6DC99C9A87E22
4 changed files with 65 additions and 4 deletions

View file

@ -531,9 +531,9 @@ r := huma.NewRouter(&huma.OpenAPI{
// For this:
g := gin.New()
g.Use(gin.Recovery())
g.Use(cors.Default())
g.Use(huma.Recovery())
g.Use(huma.LogMiddleware(nil, nil))
g.Use(cors.Default())
r := huma.NewRouterWithGin(g, &huma.OpenAPI{
Title: "Notes API",
Version: "1.0.0",

View file

@ -2,6 +2,7 @@ package huma
import (
"fmt"
"net/http"
"os"
"time"
@ -13,6 +14,26 @@ import (
var logLevel *zap.AtomicLevel
// Recovery prints stack traces on panic when used with the logging middleware.
func Recovery() func(*gin.Context) {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
if l, ok := c.Get("log"); ok {
if log, ok := l.(*zap.SugaredLogger); ok {
log.With(zap.Error(err.(error))).Error("Caught panic")
}
}
c.AbortWithStatusJSON(http.StatusInternalServerError, &ErrorModel{
Message: "Internal server error",
})
}
}()
c.Next()
}
}
// NewLogger returns a new low-level `*zap.Logger` instance. If the current
// terminal is a TTY, it will try ot use colored output automatically.
func NewLogger() (*zap.Logger, error) {

40
middleware_test.go Normal file
View file

@ -0,0 +1,40 @@
package huma
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"go.uber.org/zap/zaptest"
)
func TestRecoveryMiddleware(t *testing.T) {
g := gin.New()
l := zaptest.NewLogger(t)
g.Use(LogMiddleware(l, nil))
g.Use(Recovery())
r := NewRouterWithGin(g, &OpenAPI{Title: "My API", Version: "1.0.0"})
r.Register(&Operation{
Method: http.MethodGet,
Path: "/panic",
Description: "Panic recovery test",
Responses: []*Response{
ResponseText(http.StatusOK, "Success"),
},
Handler: func() string {
panic(fmt.Errorf("Some error"))
},
})
w := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/panic", nil)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Equal(t, "application/json; charset=utf-8", w.Result().Header.Get("content-type"))
}

View file

@ -171,9 +171,9 @@ type Router struct {
// CORS (allowing all origins), and log middlewares.
func NewRouter(api *OpenAPI) *Router {
g := gin.New()
g.Use(gin.Recovery())
g.Use(cors.Default())
g.Use(Recovery())
g.Use(LogMiddleware(nil, nil))
g.Use(cors.Default())
return NewRouterWithGin(g, api)
}