Skip to content

Commit b3d6739

Browse files
committed
Replace Chi with Standard Library
Preserve existing behavior and ease maintenance by reducing external dependencies. - Create custom router (`CustomServeMux`) to replace `go-chi/chi/v5`. Also, replace the few middlewares to eliminate other Chi imports. - Implement `bat-go` style error handling without a dependency using `AppError` type and handler - Consolidate routing to make it easier to understand the whole interface in one place.
1 parent 8336150 commit b3d6739

File tree

11 files changed

+738
-341
lines changed

11 files changed

+738
-341
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ docker-dev:
66

77
docker-test:
88
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm -p 2416:2416 challenge-bypass bash -c \
9-
"(aws dynamodb delete-table \
9+
"export AWS_PAGER='' && (aws dynamodb delete-table \
1010
--table-name redemptions --endpoint-url http://dynamodb:8000 --region us-west-2 || \
1111
aws dynamodb create-table \
1212
--attribute-definitions AttributeName=id,AttributeType=S \

go.mod

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ require (
1111
github.com/brave-intl/bat-go/libs v0.0.0-20250515184320-890ea7676fc7
1212
github.com/brave-intl/challenge-bypass-ristretto-ffi v0.0.0-20220418231828-419995e4a873
1313
github.com/getsentry/raven-go v0.2.0
14-
github.com/go-chi/chi/v5 v5.2.2
15-
github.com/go-chi/httplog/v3 v3.2.2
1614
github.com/golang-migrate/migrate/v4 v4.18.3
1715
github.com/google/uuid v1.6.0
1816
github.com/jmoiron/sqlx v1.3.5
@@ -23,7 +21,7 @@ require (
2321
github.com/satori/go.uuid v1.2.0
2422
github.com/segmentio/kafka-go v0.4.38
2523
github.com/segmentio/kafka-go/sasl/aws_msk_iam_v2 v0.1.0
26-
github.com/stretchr/testify v1.9.0
24+
github.com/stretchr/testify v1.10.0
2725
)
2826

2927
require (

go.sum

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,6 @@ github.com/getsentry/sentry-go v0.17.0 h1:UustVWnOoDFHBS7IJUB2QK/nB5pap748ZEp0sw
102102
github.com/getsentry/sentry-go v0.17.0/go.mod h1:B82dxtBvxG0KaPD8/hfSV+VcHD+Lg/xUS4JuQn1P4cM=
103103
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
104104
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
105-
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
106-
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
107-
github.com/go-chi/httplog/v3 v3.2.2 h1:G0oYv3YYcikNjijArHFUlqfR78cQNh9fGT43i6StqVc=
108-
github.com/go-chi/httplog/v3 v3.2.2/go.mod h1:N/J1l5l1fozUrqIVuT8Z/HzNeSy8TF2EFyokPLe6y2w=
109105
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
110106
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
111107
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@@ -254,8 +250,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
254250
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
255251
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
256252
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
257-
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
258-
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
253+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
254+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
259255
github.com/throttled/throttled/v2 v2.12.0 h1:IezKE1uHlYC/0Al05oZV6Ar+uN/znw3cy9J8banxhEY=
260256
github.com/throttled/throttled/v2 v2.12.0/go.mod h1:+EAvrG2hZAQTx8oMpBu8fq6Xmm+d1P2luKK7fIY1Esc=
261257
github.com/xdg/scram v1.0.5 h1:TuS0RFmt5Is5qm9Tm2SoD89OPqe4IRiFtyFY4iwWXsw=

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func main() {
2828
Commit = "none"
2929
)
3030

31-
serverCtx, logger := server.SetupLogger(context.Background(), Version, BuildTime, Commit)
31+
logger := server.SetupLogger(Version, BuildTime, Commit)
3232
srv := *server.DefaultServer
3333
srv.Logger = logger
3434

@@ -90,7 +90,7 @@ func main() {
9090
}
9191

9292
logger.Debug("Initializing API server")
93-
err = srv.ListenAndServe(serverCtx, logger)
93+
err = srv.ListenAndServe(logger)
9494
if err != nil {
9595
logger.Error("listenandserve", slog.Any("error", err))
9696
raven.CaptureErrorAndWait(err, nil)

server/app_handler.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package server
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"log/slog"
7+
"net/http"
8+
)
9+
10+
// AppError defines an application error with cause, message and HTTP status code
11+
type AppError struct {
12+
Cause error `json:"-"`
13+
Message string `json:"message"`
14+
Code int `json:"-"`
15+
}
16+
17+
// Error returns the error message
18+
func (e *AppError) Error() string {
19+
if e.Cause != nil {
20+
return fmt.Sprintf("%s: %s", e.Message, e.Cause.Error())
21+
}
22+
return e.Message
23+
}
24+
25+
// WrapError creates a new AppError from an error
26+
func WrapError(err error, message string, code int) *AppError {
27+
return &AppError{
28+
Cause: err,
29+
Message: message,
30+
Code: code,
31+
}
32+
}
33+
34+
// RenderContent renders JSON content with appropriate status code
35+
func RenderContent(content any, w http.ResponseWriter, statusCode int) error {
36+
w.Header().Set("Content-Type", "application/json; charset=utf-8")
37+
w.WriteHeader(statusCode)
38+
if content == nil {
39+
// Return empty JSON object instead of null
40+
_, err := w.Write([]byte("{}"))
41+
return err
42+
}
43+
return json.NewEncoder(w).Encode(content)
44+
}
45+
46+
// AppHandler is a custom HTTP handler type that returns an AppError
47+
type AppHandler func(http.ResponseWriter, *http.Request) *AppError
48+
49+
// ServeHTTP makes AppHandler satisfy the http.Handler interface
50+
func (fn AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
51+
if err := fn(w, r); err != nil {
52+
// Log the error
53+
if logger, ok := r.Context().Value("logger").(*slog.Logger); ok && err.Cause != nil {
54+
logger.Error("handler error",
55+
slog.String("message", err.Message),
56+
slog.Any("error", err.Cause))
57+
}
58+
// Render the error response
59+
w.Header().Set("Content-Type", "application/json; charset=utf-8")
60+
w.WriteHeader(err.Code)
61+
// Create the error response
62+
errorResponse := map[string]string{"message": err.Message}
63+
if err := json.NewEncoder(w).Encode(errorResponse); err != nil {
64+
// If we can't encode the error response, log it and send a plain text error
65+
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
66+
}
67+
}
68+
}

server/db.go

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"log/slog"
99
"os"
10+
"strconv"
1011
"time"
1112

1213
"github.com/brave-intl/challenge-bypass-server/model"
@@ -63,9 +64,9 @@ type RedemptionV2 struct {
6364

6465
// CacheInterface cache functions
6566
type CacheInterface interface {
66-
Get(k string) (interface{}, bool)
67+
Get(k string) (any, bool)
6768
Delete(k string)
68-
SetDefault(k string, x interface{})
69+
SetDefault(k string, x any)
6970
}
7071

7172
var (
@@ -80,6 +81,51 @@ func (c *Server) LoadDBConfig(config DBConfig) {
8081
c.dbConfig = config
8182
}
8283

84+
// InitDBConfig reads os environment and update conf
85+
func (c *Server) InitDBConfig() error {
86+
conf := DBConfig{
87+
DefaultDaysBeforeExpiry: 7,
88+
DefaultIssuerValidDays: 30,
89+
MaxConnection: 100,
90+
}
91+
// Heroku style
92+
if connectionURI := os.Getenv("DATABASE_URL"); connectionURI != "" {
93+
conf.ConnectionURI = os.Getenv("DATABASE_URL")
94+
}
95+
if dynamodbEndpoint := os.Getenv("DYNAMODB_ENDPOINT"); dynamodbEndpoint != "" {
96+
conf.DynamodbEndpoint = os.Getenv("DYNAMODB_ENDPOINT")
97+
}
98+
if maxConnection := os.Getenv("MAX_DB_CONNECTION"); maxConnection != "" {
99+
if count, err := strconv.Atoi(maxConnection); err == nil {
100+
conf.MaxConnection = count
101+
}
102+
}
103+
if defaultDaysBeforeExpiry := os.Getenv("DEFAULT_DAYS_BEFORE_EXPIRY"); defaultDaysBeforeExpiry != "" {
104+
if count, err := strconv.Atoi(defaultDaysBeforeExpiry); err == nil {
105+
conf.DefaultDaysBeforeExpiry = count
106+
}
107+
}
108+
if defaultIssuerValidDays := os.Getenv("DEFAULT_ISSUER_VALID_DAYS"); defaultIssuerValidDays != "" {
109+
if count, err := strconv.Atoi(defaultIssuerValidDays); err == nil {
110+
conf.DefaultIssuerValidDays = count
111+
}
112+
}
113+
if cacheEnabled := os.Getenv("CACHE_ENABLED"); cacheEnabled == "true" {
114+
cachingConfig := CachingConfig{
115+
Enabled: true,
116+
ExpirationSec: 10,
117+
}
118+
if cacheDurationSecs := os.Getenv("CACHE_DURATION_SECS"); cacheDurationSecs != "" {
119+
if secs, err := strconv.Atoi(cacheDurationSecs); err == nil {
120+
cachingConfig.ExpirationSec = secs
121+
}
122+
}
123+
conf.CachingConfig = cachingConfig
124+
}
125+
c.LoadDBConfig(conf)
126+
return nil
127+
}
128+
83129
// InitDB initialzes the database connection based on a server's configuration
84130
func (c *Server) InitDB() {
85131
cfg := c.dbConfig

0 commit comments

Comments
 (0)