2023-09-17
Fiber でウェブアプリケーションを作ってます。
panic が起きた時に recover し、レスポンスをカスタマイズしてみました。
パニックをリカバーする
まず panic を recover するために Recover middleware を入れます。
package main import ( "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/recover" ) func main() { app := fiber.New(fiber.Config{}) // リカバーミドルウェア app.Use(recover.New(recover.Config{ EnableStackTrace: true, })) // ルーティング app.Get("/", func(c *fiber.Ctx) error { // パニック panic("uncaught error") }) app.Listen(":3000") }
呼んでみます
$ curl http://localhost:3000/ --verbose * Trying 127.0.0.1:3000... * Connected to localhost (127.0.0.1) port 3000 (#0) > GET / HTTP/1.1 > Host: localhost:3000 > User-Agent: curl/8.1.2 > Accept: */* > < HTTP/1.1 500 Internal Server Error < Date: Sat, 16 Sep 2023 19:30:59 GMT < Content-Type: text/plain; charset=utf-8 < Content-Length: 14 < * Connection #0 to host localhost left intact uncaught error
panic が発生しましたが、レスポンスを返せました。
ステータスは 500 でレスポンスボディにエラーメッセージが入ってます。
エラーレスポンスをカスタマイズする
続いて、このエラーレスポンスをカスタマイズします。
方法ですがドキュメントに記載ありました。fiber.Config の ErrorHandler で制御できます
app := fiber.New(fiber.Config{ ErrorHandler: func (ctx *fiber.Ctx, err error) error { // handle error here return nil }, })
ちなみに、デフォルトのエラーハンドラでステータスコードの指定などしているようです。 ドキュメントに記載されているので実装の際は見ておいた方が良さそうです。
指定のエラーレスポンスを返す
ウェブAPIなのでJSONを返せるようにします。上記の ErrorHandler を用います。
package main import ( "errors" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/recover" ) // エラーレスポンスのボディ type ErrorResponse struct { Error string `json:"error"` } // エラーハンドラ func errorHandler(ctx *fiber.Ctx, err error) error { code := fiber.StatusInternalServerError var e *fiber.Error if errors.As(err, &e) { code = e.Code } // JSONを返す return ctx.Status(code).JSON(ErrorResponse { Error: "Internal Sever Error" }) } func main() { app := fiber.New(fiber.Config{ // エラーハンドラを指定 ErrorHandler: errorHandler, }) // リカバーミドルウェア app.Use(recover.New(recover.Config{ EnableStackTrace: true, })) // ルーティング app.Get("/", func(c *fiber.Ctx) error { // パニック panic("uncaught error") }) app.Listen(":3000") }
呼んでみます
$ curl http://localhost:3000/ --verbose * Trying 127.0.0.1:3000... * Connected to localhost (127.0.0.1) port 3000 (#0) > GET / HTTP/1.1 > Host: localhost:3000 > User-Agent: curl/8.1.2 > Accept: */* > < HTTP/1.1 500 Internal Server Error < Date: Sat, 16 Sep 2023 19:52:01 GMT < Content-Type: application/json < Content-Length: 32 < * Connection #0 to host localhost left intact {"error":"Internal Sever Error"}
JSONを返せました。
終わりに
try catch がある言語ではトップレベルで try catch すれば良いかと思います。
Go言語の場合、そもそも1つずつエラーハンドリングする必要があり、 また panic が起きることが少ないので、あまり気にしてませんでした。
実運用を考えると用心する意味合いで入れた方が良さそうです。
作成日
2023-09-17
更新日
2023-09-17