tenseleyflow/shithub / 828eb18

Browse files

api: wire apilimit + meta into Mount, expose BaseURL/APILimit on Deps

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
828eb184ba854003bc59fb17c7ab0d5939866dca
Parents
8bbbb65
Tree
c396e77

1 changed file

StatusFile+-
M internal/web/handlers/api/api.go 21 0
internal/web/handlers/api/api.gomodified
@@ -24,6 +24,7 @@ import (
2424
 	"github.com/tenseleyFlow/shithub/internal/infra/storage"
2525
 	"github.com/tenseleyFlow/shithub/internal/ratelimit"
2626
 	usersdb "github.com/tenseleyFlow/shithub/internal/users/sqlc"
27
+	"github.com/tenseleyFlow/shithub/internal/web/handlers/api/apilimit"
2728
 	"github.com/tenseleyFlow/shithub/internal/web/middleware"
2829
 )
2930
 
@@ -38,6 +39,12 @@ type Deps struct {
3839
 	RunnerJWT   *runnerjwt.Signer
3940
 	SecretBox   *secretbox.Box
4041
 	RateLimiter *ratelimit.Limiter
42
+	// BaseURL is the public scheme://host prefix used for absolute
43
+	// pagination Link headers. Empty falls back to path-relative URLs.
44
+	BaseURL string
45
+	// APILimit configures the /api/v1/* rate-limit middleware. Zero
46
+	// values inherit apilimit.Middleware's no-op fallback.
47
+	APILimit apilimit.Config
4148
 }
4249
 
4350
 // Handlers is the registered API handler set. Construct with New.
@@ -77,9 +84,20 @@ const runnerAPIMaxBodyBytes = 768 * 1024
7784
 
7885
 // Mount registers /api/v1/* on r. Caller is responsible for putting r
7986
 // in a CSRF-exempt group.
87
+//
88
+// Outer middleware on every /api/v1/* request: apilimit stamps the
89
+// X-RateLimit-* headers and refuses over-budget callers with a JSON
90
+// 429. Inner groups attach body caps, PAT auth, and scope decorators
91
+// according to the surface they expose.
8092
 func (h *Handlers) Mount(r chi.Router) {
93
+	apiLimitMW := apilimit.Middleware(h.d.RateLimiter, apilimit.Config{
94
+		AuthedPerHour: h.d.APILimit.AuthedPerHour,
95
+		AnonPerHour:   h.d.APILimit.AnonPerHour,
96
+		Logger:        h.d.Logger,
97
+	})
8198
 	r.Group(func(r chi.Router) {
8299
 		r.Use(middleware.MaxBodySize(runnerAPIMaxBodyBytes))
100
+		r.Use(apiLimitMW)
83101
 		h.mountRunners(r)
84102
 	})
85103
 	r.Group(func(r chi.Router) {
@@ -88,6 +106,9 @@ func (h *Handlers) Mount(r chi.Router) {
88106
 			Pool:      h.d.Pool,
89107
 			Debouncer: h.d.Debouncer,
90108
 		}))
109
+		r.Use(apiLimitMW)
110
+		// /meta is capability discovery — no scope required, anon ok.
111
+		h.mountMeta(r)
91112
 		r.Group(func(r chi.Router) {
92113
 			r.Use(middleware.RequireScope(pat.ScopeUserRead))
93114
 			r.Get("/api/v1/user", h.userMe)