HTTP роутер для Go с обработкой ошибок
BunRouter это чрезвычайно быстрый Golang router с уникальной комбинацией возможностей:
Мидлвары (middlewares) позволяют вынести общий функционал из HTTP обработчиков в отдельные функции.
Встроенная обработка ошибок позволяет снизить размер HTTP функций и обрабатывать ошибки в мидлварах.
Минималистическое и совместимое АПИ, которое не пытается делать все сразу: от обработки статичный файлов до генерации XML (
gin.Context
иecho.Context
грешат этим).
И да, он очень быстр, хотя и уступает роутам использующим fasthttp.
Введение
По умолчанию BunRouter использует слегка улучшенную версию http.HandlerFunc
, которая принимает bunrouter.Request
и возвращает ошибки:
import "github.com/uptrace/bunrouter"
router := bunrouter.New(
bunrouter.Use(reqlog.NewMiddleware()),
)
router.WithGroup("/api", func(g *bunrouter.Group) {
g.GET("/users/:id", debugHandler)
g.GET("/users/current", debugHandler)
g.GET("/users/*path", debugHandler)
})
func debugHandler(w http.ResponseWriter, req bunrouter.Request) error {
// use req.Request to get *http.Request
return bunrouter.JSON(w, bunrouter.H{
"route": req.Route(),
"params": req.Params().Map(),
})
}
Но не пугайтесь, BunRouter также умеет работать и с классическими http.HandlerFunc
.
BunRouter поддерживает всего 2 типа параметров в роутах:
:param
это именованный параметр который совпадает с одним сегментом из пути (текстом между слэшами).*param
это "звездный" параметр, которые совпадает со всем и всегда должен идти в конце роута.
К примеру, /users/:id
совпадает с /users/123
и /users/foo-bar
, но не с /users/foo/bar
.
Мидлвары
Мидлвары позволяют вынести общий функционал в отдельные функции, к примеру, вы можете написать мидлвар, который логирует обработанные запросы:
func middleware(next bunrouter.HandlerFunc) bunrouter.HandlerFunc {
// you can initialize the middleware here
// Return the middleware.
return func(w http.ResponseWriter, req bunrouter.Request) error {
rec := httptest.NewRecorder()
// Pass the recorder instead of http.ResponseWriter.
if err := next(rec, req); err != nil {
fmt.Printf("%s %s failed: %s\n", req.Method, req.Route(), err)
// Discard the error.
return nil
}
fmt.Printf("%s %s returned %d\n", req.Method, req.Route(), rec.Code)
}
}
Мидлвары затем может использовать следующим образом:
router.Use(middleware).WithGroup(...)
// либо
group = group.Use(middleware)
Обработка ошибок
Как вы уже могли заметить, обработчики BunRouter возвращают ошибки, которые вы затем можете обработать в мидлварах:
func errorHandler(next bunrouter.HandlerFunc) bunrouter.HandlerFunc {
return func(w http.ResponseWriter, req bunrouter.Request) error {
// Call the next handler on the chain to get the error.
err := next(w, req)
switch err := err.(type) {
case nil:
// no error
case HTTPError: // already a HTTPError
w.WriteHeader(err.statusCode)
_ = bunrouter.JSON(w, err)
default:
httpErr := NewHTTPError(err)
w.WriteHeader(httpErr.statusCode)
_ = bunrouter.JSON(w, httpErr)
}
return err // return the err in case there other middlewares
}
}
За деталями обращайтесь к документации по HTTP error handling.
Приоритет роутов
Приоритет роутов зависит от типов параметров и сегментов и не зависит от порядка объявления роутов:
Сначала срабатывают статичные сегменты, к примеру,
/users/
.Затем именованные параметры, к примеру,
:id
.И в последнюю очередь "звездные" параметры, к примеру,
*path
.
Для понимания рассмотрим следующие роуты отсортированные по приоритету срабатывания:
/users/list
- статичный роут./users/:id
- роут с именованным параметром./users/*path
- роут с "звездным" параметром.
Что дальше
Чтобы начать использовать BunRouter, обращайтесь к документации или сразу попробуйте запустить примеры.
BunRouter имеет множестов плагинов, к примеру, OpenTelemetry инструментация, которая поддерживает OpenTelemetry tracing и метрики.
Используя трейсинг, вы можете мониторить производительность, используя полностью бесплатные distributed tracing tools с открытым кодом.
Вы также можете экспортировать собранные метрики в Prometheus metrics, чтобы затем отобразить их в Grafana alternatives.