Skip to content

Commit 28efebb

Browse files
authored
Use net/http router instead of chi (#215)
1 parent 3d1c859 commit 28efebb

File tree

7 files changed

+79
-50
lines changed

7 files changed

+79
-50
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ require (
1212
github.com/charmbracelet/ssh v0.0.0-20240725163421-eb71b85b27aa
1313
github.com/charmbracelet/wish v1.4.3
1414
github.com/dustin/go-humanize v1.0.1
15-
github.com/go-chi/chi/v5 v5.1.0
1615
github.com/jaevor/go-nanoid v1.4.0
1716
github.com/kelseyhightower/envconfig v1.4.0
1817
github.com/klauspost/compress v1.17.10

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e h
8282
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e/go.mod h1:TelZuq26kz2jysARBwOrTv16629hyUsHmIoj54QqyFo=
8383
github.com/galeone/tfgo v0.0.0-20230214145115-56cedbc50978 h1:8xhEVC2zjvI+3xWkt+78Krkd6JYp+0+iEoBVi0UBlJs=
8484
github.com/galeone/tfgo v0.0.0-20230214145115-56cedbc50978/go.mod h1:3YgYBeIX42t83uP27Bd4bSMxTnQhSbxl0pYSkCDB1tc=
85-
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
86-
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
8785
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
8886
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
8987
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=

internal/http/assets.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ var (
4545
type Assets interface {
4646
Doc(filename string) ([]byte, error)
4747
Template() *template.Template
48-
ServeJS(w http.ResponseWriter, r *http.Request)
49-
ServeCSS(w http.ResponseWriter, r *http.Request)
48+
Serve(w http.ResponseWriter, r *http.Request)
5049
}
5150

5251
type StaticAssets struct {
@@ -137,12 +136,15 @@ func (a *StaticAssets) Template() *template.Template {
137136
return a.tmpl
138137
}
139138

140-
func (a *StaticAssets) ServeJS(w http.ResponseWriter, r *http.Request) {
141-
serve(w, r, a.js, jsMime)
142-
}
143-
144-
func (a *StaticAssets) ServeCSS(w http.ResponseWriter, r *http.Request) {
145-
serve(w, r, a.css, cssMime)
139+
func (a *StaticAssets) Serve(w http.ResponseWriter, r *http.Request) {
140+
switch r.PathValue("asset") {
141+
case "index.js":
142+
serve(w, r, a.js, jsMime)
143+
case "index.css":
144+
serve(w, r, a.css, cssMime)
145+
default:
146+
http.NotFound(w, r)
147+
}
146148
}
147149

148150
// serve serves the content, gzipped if the client accepts it.

internal/http/handlers.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import (
44
"encoding/json"
55
"html/template"
66
"net/http"
7+
"net/http/pprof"
78
"net/url"
89
"strings"
910

1011
"github.com/dustin/go-humanize"
11-
"github.com/go-chi/chi/v5"
1212
"github.com/robherley/snips.sh/internal/config"
1313
"github.com/robherley/snips.sh/internal/db"
1414
"github.com/robherley/snips.sh/internal/logger"
@@ -22,6 +22,24 @@ func HealthHandler(w http.ResponseWriter, _ *http.Request) {
2222
_, _ = w.Write([]byte("💚\n"))
2323
}
2424

25+
func ProfileHandler(w http.ResponseWriter, r *http.Request) {
26+
profiler := r.PathValue("profile")
27+
switch profiler {
28+
case "cmdline":
29+
pprof.Cmdline(w, r)
30+
case "profile":
31+
pprof.Profile(w, r)
32+
case "symbol":
33+
pprof.Symbol(w, r)
34+
case "trace":
35+
pprof.Trace(w, r)
36+
default:
37+
// Available profiles can be found in [runtime/pprof.Profile].
38+
// https://pkg.go.dev/runtime/pprof#Profile
39+
pprof.Handler(profiler).ServeHTTP(w, r)
40+
}
41+
}
42+
2543
func MetaHandler(cfg *config.Config) http.HandlerFunc {
2644
return func(w http.ResponseWriter, _ *http.Request) {
2745
w.Header().Set("Content-Type", "application/json")
@@ -53,7 +71,7 @@ func DocHandler(assets Assets) http.HandlerFunc {
5371
return func(w http.ResponseWriter, r *http.Request) {
5472
log := logger.From(r.Context())
5573

56-
name := chi.URLParam(r, "name")
74+
name := r.PathValue("name")
5775
if name == "" {
5876
name = "README.md"
5977
}
@@ -94,8 +112,7 @@ func FileHandler(cfg *config.Config, database db.DB, assets Assets) http.Handler
94112
return func(w http.ResponseWriter, r *http.Request) {
95113
log := logger.From(r.Context())
96114

97-
fileID := chi.URLParam(r, "fileID")
98-
115+
fileID := r.PathValue("fileID")
99116
if fileID == "" {
100117
http.NotFound(w, r)
101118
return

internal/http/middleware.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,34 @@ package http
33
import (
44
"context"
55
"net/http"
6+
"strings"
67
"time"
78

89
"github.com/armon/go-metrics"
9-
"github.com/go-chi/chi/v5"
1010
"github.com/robherley/snips.sh/internal/id"
1111
"github.com/robherley/snips.sh/internal/logger"
1212
"github.com/rs/zerolog/log"
1313
)
1414

15+
type Middleware func(next http.Handler) http.Handler
16+
17+
var DefaultMiddleware = []Middleware{
18+
WithRecover,
19+
WithMetrics,
20+
WithLogger,
21+
WithRequestID,
22+
}
23+
24+
func WithMiddleware(handler http.Handler, middlewares ...Middleware) http.Handler {
25+
middlewares = append(DefaultMiddleware, middlewares...)
26+
27+
withMiddleware := handler
28+
for i := range middlewares {
29+
withMiddleware = middlewares[i](withMiddleware)
30+
}
31+
return withMiddleware
32+
}
33+
1534
// WithRequestID adds a unique request ID to the request context.
1635
func WithRequestID(next http.Handler) http.Handler {
1736
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -40,9 +59,10 @@ func WithLogger(next http.Handler) http.Handler {
4059
ctx := context.WithValue(r.Context(), logger.ContextKey, &reqLog)
4160
reqLog.Info().Msg("connected")
4261

43-
next.ServeHTTP(w, r.WithContext(ctx))
62+
r = r.WithContext(ctx)
63+
next.ServeHTTP(w, r)
4464

45-
reqLog.Info().Dur("dur", time.Since(start)).Msg("disconnected")
65+
reqLog.Info().Dur("dur", time.Since(start)).Str("pattern", Pattern(r)).Msg("disconnected")
4666
})
4767
}
4868

@@ -65,19 +85,21 @@ func WithMetrics(next http.Handler) http.Handler {
6585
start := time.Now()
6686
next.ServeHTTP(w, r)
6787

68-
rctx := chi.RouteContext(r.Context())
69-
pattern := rctx.RoutePattern()
70-
if pattern == "" {
71-
// empty pattern, didn't match router e.g. 404
72-
pattern = "*"
73-
}
74-
7588
labels := []metrics.Label{
76-
{Name: "path", Value: pattern},
89+
{Name: "pattern", Value: Pattern(r)},
7790
{Name: "method", Value: r.Method},
7891
}
7992

8093
metrics.IncrCounterWithLabels([]string{"http", "request"}, 1, labels)
8194
metrics.MeasureSinceWithLabels([]string{"http", "request", "duration"}, start, labels)
8295
})
8396
}
97+
98+
func Pattern(r *http.Request) string {
99+
pattern := strings.TrimPrefix(r.Pattern, r.Method+" ")
100+
if pattern == "" {
101+
// empty pattern, didn't match router e.g. 404
102+
pattern = "*"
103+
}
104+
return pattern
105+
}

internal/http/service.go

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,32 @@ package http
33
import (
44
"net/http"
55

6-
"github.com/go-chi/chi/v5"
7-
"github.com/go-chi/chi/v5/middleware"
86
"github.com/robherley/snips.sh/internal/config"
97
"github.com/robherley/snips.sh/internal/db"
108
)
119

1210
type Service struct {
1311
*http.Server
14-
Router *chi.Mux
1512
}
1613

1714
func New(cfg *config.Config, database db.DB, assets Assets) (*Service, error) {
18-
router := chi.NewRouter()
15+
mux := http.NewServeMux()
1916

20-
router.Use(WithRequestID)
21-
router.Use(WithLogger)
22-
router.Use(WithMetrics)
23-
router.Use(WithRecover)
24-
25-
router.Get("/", DocHandler(assets))
26-
router.Get("/docs/{name}", DocHandler(assets))
27-
router.Get("/health", HealthHandler)
28-
router.Get("/f/{fileID}", FileHandler(cfg, database, assets))
29-
router.Get("/assets/index.js", assets.ServeJS)
30-
router.Get("/assets/index.css", assets.ServeCSS)
31-
router.Get("/meta.json", MetaHandler(cfg))
17+
mux.HandleFunc("GET /{$}", DocHandler(assets))
18+
mux.HandleFunc("GET /docs/{name}", DocHandler(assets))
19+
mux.HandleFunc("GET /health", HealthHandler)
20+
mux.HandleFunc("GET /f/{fileID}", FileHandler(cfg, database, assets))
21+
mux.HandleFunc("GET /assets/{asset}", assets.Serve)
22+
mux.HandleFunc("GET /meta.json", MetaHandler(cfg))
3223

3324
if cfg.Debug {
34-
router.Mount("/_debug", middleware.Profiler())
35-
}
36-
37-
httpServer := &http.Server{
38-
Addr: cfg.HTTP.Internal.Host,
39-
Handler: router,
25+
mux.HandleFunc("/_debug/pprof/{profile}", ProfileHandler)
4026
}
4127

42-
return &Service{httpServer, router}, nil
28+
return &Service{
29+
&http.Server{
30+
Addr: cfg.HTTP.Internal.Host,
31+
Handler: WithMiddleware(mux),
32+
},
33+
}, nil
4334
}

internal/http/service_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func (suite *HTTPServiceSuite) SetupTest() {
4747
}
4848

4949
func (suite *HTTPServiceSuite) TestHTTPServer() {
50-
ts := httptest.NewServer(suite.service.Router)
50+
ts := httptest.NewServer(suite.service.Handler)
5151
defer ts.Close()
5252

5353
signedFileID := "wdHzc62hsn"

0 commit comments

Comments
 (0)