Skip to content

Commit d7788d6

Browse files
blgmzucchinidev
andauthored
feat!: remove dependency on go-chi/chi (#340)
BREAKING CHANGE In Go 1.22, http.ServeMux was improved so that we no longer need to use go-chi/chi, gorilla/mux, or any other thrid party HTTP router. The advantage to consumers is that they can use any router, or none, and do not have a dependency forced on them. Public API changes: - `New()` has changed signature to optionally take options. - `AttachRoutes()` has been removed. If you want to attach to an existing Chi router, you can still do something like: ```go b := brokerapi.New(broker, logger, brokerapi.WithBrokerCredentials(creds)) r := chi.NewRouter() r.Handle("/*", b) ``` - The `WithRouter()` option has been removed as a Chi router can no longer be specified. - `WithEncodedPath()` has been removed as it was deprecated and did nothing. Co-authored-by: Andrea Zucchini <[email protected]>
1 parent a0966ec commit d7788d6

19 files changed

+286
-245
lines changed

api.go

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,103 @@ import (
1919
"log/slog"
2020
"net/http"
2121

22-
"github.com/go-chi/chi/v5"
22+
"github.com/pivotal-cf/brokerapi/v11/internal/middleware"
23+
24+
"github.com/pivotal-cf/brokerapi/v11/auth"
25+
"github.com/pivotal-cf/brokerapi/v11/domain"
2326
"github.com/pivotal-cf/brokerapi/v11/handlers"
27+
"github.com/pivotal-cf/brokerapi/v11/middlewares"
2428
)
2529

2630
type BrokerCredentials struct {
2731
Username string
2832
Password string
2933
}
3034

31-
func New(serviceBroker ServiceBroker, logger *slog.Logger, brokerCredentials BrokerCredentials) http.Handler {
32-
return NewWithOptions(serviceBroker, logger, WithBrokerCredentials(brokerCredentials))
35+
func New(serviceBroker domain.ServiceBroker, logger *slog.Logger, brokerCredentials BrokerCredentials, opts ...Option) http.Handler {
36+
return NewWithOptions(serviceBroker, logger, append([]Option{WithBrokerCredentials(brokerCredentials)}, opts...)...)
37+
}
38+
39+
func NewWithOptions(serviceBroker domain.ServiceBroker, logger *slog.Logger, opts ...Option) http.Handler {
40+
var cfg config
41+
WithOptions(opts...)(&cfg)
42+
43+
mw := append(append(cfg.authMiddleware, defaultMiddleware(logger)...), cfg.additionalMiddleware...)
44+
r := router(serviceBroker, logger)
45+
46+
return middleware.Use(r, mw...)
3347
}
3448

35-
func NewWithCustomAuth(serviceBroker ServiceBroker, logger *slog.Logger, authMiddleware middlewareFunc) http.Handler {
49+
func NewWithCustomAuth(serviceBroker domain.ServiceBroker, logger *slog.Logger, authMiddleware func(handler http.Handler) http.Handler) http.Handler {
3650
return NewWithOptions(serviceBroker, logger, WithCustomAuth(authMiddleware))
3751
}
3852

39-
func AttachRoutes(router chi.Router, serviceBroker ServiceBroker, logger *slog.Logger) {
40-
attachRoutes(router, serviceBroker, logger)
53+
type config struct {
54+
authMiddleware []func(http.Handler) http.Handler
55+
additionalMiddleware []func(http.Handler) http.Handler
56+
}
57+
58+
type Option func(*config)
59+
60+
func WithBrokerCredentials(brokerCredentials BrokerCredentials) Option {
61+
return func(c *config) {
62+
c.authMiddleware = append(c.authMiddleware, auth.NewWrapper(brokerCredentials.Username, brokerCredentials.Password).Wrap)
63+
}
64+
}
65+
66+
// WithCustomAuth adds the specified middleware *before* any other middleware.
67+
// Despite the name, any middleware can be added whether nor not it has anything to do with authentication.
68+
// But `WithAdditionalMiddleware()` may be a better choice if the middleware is not related to authentication.
69+
// Can be called multiple times.
70+
func WithCustomAuth(authMiddleware func(handler http.Handler) http.Handler) Option {
71+
return func(c *config) {
72+
c.authMiddleware = append(c.authMiddleware, authMiddleware)
73+
}
74+
}
75+
76+
// WithAdditionalMiddleware adds the specified middleware *after* the default middleware.
77+
// Can be called multiple times.
78+
func WithAdditionalMiddleware(m func(http.Handler) http.Handler) Option {
79+
return func(c *config) {
80+
c.additionalMiddleware = append(c.additionalMiddleware, m)
81+
}
82+
}
83+
84+
func WithOptions(opts ...Option) Option {
85+
return func(c *config) {
86+
for _, o := range opts {
87+
o(c)
88+
}
89+
}
4190
}
4291

43-
func attachRoutes(router chi.Router, serviceBroker ServiceBroker, logger *slog.Logger) {
92+
func router(serviceBroker ServiceBroker, logger *slog.Logger) http.Handler {
4493
apiHandler := handlers.NewApiHandler(serviceBroker, logger)
45-
router.Get("/v2/catalog", apiHandler.Catalog)
94+
r := http.NewServeMux()
95+
r.HandleFunc("GET /v2/catalog", apiHandler.Catalog)
4696

47-
router.Get("/v2/service_instances/{instance_id}", apiHandler.GetInstance)
48-
router.Put("/v2/service_instances/{instance_id}", apiHandler.Provision)
49-
router.Delete("/v2/service_instances/{instance_id}", apiHandler.Deprovision)
50-
router.Get("/v2/service_instances/{instance_id}/last_operation", apiHandler.LastOperation)
51-
router.Patch("/v2/service_instances/{instance_id}", apiHandler.Update)
97+
r.HandleFunc("PUT /v2/service_instances/{instance_id}", apiHandler.Provision)
98+
r.HandleFunc("GET /v2/service_instances/{instance_id}", apiHandler.GetInstance)
99+
r.HandleFunc("PATCH /v2/service_instances/{instance_id}", apiHandler.Update)
100+
r.HandleFunc("DELETE /v2/service_instances/{instance_id}", apiHandler.Deprovision)
52101

53-
router.Get("/v2/service_instances/{instance_id}/service_bindings/{binding_id}", apiHandler.GetBinding)
54-
router.Put("/v2/service_instances/{instance_id}/service_bindings/{binding_id}", apiHandler.Bind)
55-
router.Delete("/v2/service_instances/{instance_id}/service_bindings/{binding_id}", apiHandler.Unbind)
102+
r.HandleFunc("GET /v2/service_instances/{instance_id}/last_operation", apiHandler.LastOperation)
103+
104+
r.HandleFunc("PUT /v2/service_instances/{instance_id}/service_bindings/{binding_id}", apiHandler.Bind)
105+
r.HandleFunc("GET /v2/service_instances/{instance_id}/service_bindings/{binding_id}", apiHandler.GetBinding)
106+
r.HandleFunc("DELETE /v2/service_instances/{instance_id}/service_bindings/{binding_id}", apiHandler.Unbind)
107+
108+
r.HandleFunc("GET /v2/service_instances/{instance_id}/service_bindings/{binding_id}/last_operation", apiHandler.LastBindingOperation)
109+
110+
return r
111+
}
56112

57-
router.Get("/v2/service_instances/{instance_id}/service_bindings/{binding_id}/last_operation", apiHandler.LastBindingOperation)
113+
func defaultMiddleware(logger *slog.Logger) []func(http.Handler) http.Handler {
114+
return []func(http.Handler) http.Handler{
115+
middlewares.APIVersionMiddleware{Logger: logger}.ValidateAPIVersionHdr,
116+
middlewares.AddCorrelationIDToContext,
117+
middlewares.AddOriginatingIdentityToContext,
118+
middlewares.AddInfoLocationToContext,
119+
middlewares.AddRequestIdentityToContext,
120+
}
58121
}

api_options.go

Lines changed: 0 additions & 114 deletions
This file was deleted.

api_test.go

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
"net/url"
2929
"strings"
3030

31-
"github.com/go-chi/chi/v5"
3231
. "github.com/onsi/ginkgo/v2"
3332
. "github.com/onsi/gomega"
3433
"github.com/onsi/gomega/gbytes"
@@ -109,7 +108,7 @@ var _ = Describe("Service Broker API", func() {
109108

110109
logBuffer = gbytes.NewBuffer()
111110
brokerLogger = slog.New(slog.NewJSONHandler(logBuffer, nil))
112-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithBrokerCredentials(credentials))
111+
brokerAPI = brokerapi.New(fakeServiceBroker, brokerLogger, credentials)
113112
})
114113

115114
Describe("response headers", func() {
@@ -325,7 +324,7 @@ var _ = Describe("Service Broker API", func() {
325324
}
326325

327326
BeforeEach(func() {
328-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithCustomAuth(authMiddleware))
327+
brokerAPI = brokerapi.NewWithCustomAuth(fakeServiceBroker, brokerLogger, authMiddleware)
329328
})
330329

331330
It("returns 401 when the authorization header has an incorrect bearer token", func() {
@@ -359,7 +358,7 @@ var _ = Describe("Service Broker API", func() {
359358

360359
BeforeEach(func() {
361360
fakeServiceBroker = new(fakes.AutoFakeServiceBroker)
362-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithBrokerCredentials(credentials))
361+
brokerAPI = brokerapi.New(fakeServiceBroker, brokerLogger, credentials)
363362

364363
testServer = httptest.NewServer(brokerAPI)
365364
var err error
@@ -408,7 +407,7 @@ var _ = Describe("Service Broker API", func() {
408407

409408
BeforeEach(func() {
410409
fakeServiceBroker = new(fakes.AutoFakeServiceBroker)
411-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithBrokerCredentials(credentials))
410+
brokerAPI = brokerapi.New(fakeServiceBroker, brokerLogger, credentials)
412411

413412
testServer = httptest.NewServer(brokerAPI)
414413
var err error
@@ -464,7 +463,7 @@ var _ = Describe("Service Broker API", func() {
464463

465464
BeforeEach(func() {
466465
fakeServiceBroker = new(fakes.AutoFakeServiceBroker)
467-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithBrokerCredentials(credentials))
466+
brokerAPI = brokerapi.New(fakeServiceBroker, brokerLogger, credentials)
468467

469468
testServer = httptest.NewServer(brokerAPI)
470469
var err error
@@ -520,7 +519,7 @@ var _ = Describe("Service Broker API", func() {
520519

521520
BeforeEach(func() {
522521
fakeServiceBroker = new(fakes.AutoFakeServiceBroker)
523-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithBrokerCredentials(credentials))
522+
brokerAPI = brokerapi.New(fakeServiceBroker, brokerLogger, credentials)
524523

525524
testServer = httptest.NewServer(brokerAPI)
526525
var err error
@@ -2726,24 +2725,6 @@ var _ = Describe("Service Broker API", func() {
27262725
}
27272726
})
27282727

2729-
Describe("WithRouter()", func() {
2730-
It("can take a supplied router", func() {
2731-
router := chi.NewRouter()
2732-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithRouter(router))
2733-
Expect(router).To(Equal(brokerAPI))
2734-
})
2735-
2736-
It("does not attach middleware to the router", func() {
2737-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithRouter(chi.NewRouter()))
2738-
apiVersion = "1.14" // Wrong version
2739-
2740-
instanceID := uniqueInstanceID()
2741-
response := makeInstanceProvisioningRequest(instanceID, provisionDetails, "")
2742-
Expect(response).To(HaveHTTPStatus(http.StatusCreated))
2743-
Expect(fakeServiceBroker.ProvisionedInstances).To(HaveKey(instanceID))
2744-
})
2745-
})
2746-
27472728
Describe("WithAdditionalMiddleware()", func() {
27482729
It("adds additional middleware", func() {
27492730
const (
@@ -2767,10 +2748,10 @@ var _ = Describe("Service Broker API", func() {
27672748

27682749
It("will accept URL-encoded paths", func() {
27692750
const encodedInstanceID = "foo%2Fbar"
2770-
brokerAPI = brokerapi.NewWithOptions(fakeServiceBroker, brokerLogger, brokerapi.WithBrokerCredentials(credentials))
2751+
brokerAPI = brokerapi.New(fakeServiceBroker, brokerLogger, credentials)
27712752
response := makeInstanceProvisioningRequest(encodedInstanceID, provisionDetails, "")
27722753
Expect(response).To(HaveHTTPStatus(http.StatusCreated))
2773-
Expect(fakeServiceBroker.ProvisionedInstances).To(HaveKey(encodedInstanceID))
2754+
Expect(fakeServiceBroker.ProvisionedInstances).To(HaveKey("foo/bar"))
27742755
})
27752756
})
27762757
})

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ module github.com/pivotal-cf/brokerapi/v11
33
go 1.22.1
44

55
require (
6-
github.com/go-chi/chi/v5 v5.2.0
76
github.com/google/uuid v1.6.0
87
github.com/maxbrunsfeld/counterfeiter/v6 v6.9.0
98
github.com/onsi/ginkgo/v2 v2.22.1

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF
33
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
44
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
55
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6-
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
7-
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
86
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
97
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
108
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=

handlers/bind.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"log/slog"
77
"net/http"
88

9-
"github.com/go-chi/chi/v5"
109
"github.com/pivotal-cf/brokerapi/v11/domain"
1110
"github.com/pivotal-cf/brokerapi/v11/domain/apiresponses"
1211
"github.com/pivotal-cf/brokerapi/v11/internal/blog"
@@ -19,8 +18,8 @@ const (
1918
)
2019

2120
func (h APIHandler) Bind(w http.ResponseWriter, req *http.Request) {
22-
instanceID := chi.URLParam(req, "instance_id")
23-
bindingID := chi.URLParam(req, "binding_id")
21+
instanceID := req.PathValue("instance_id")
22+
bindingID := req.PathValue("binding_id")
2423

2524
logger := h.logger.Session(req.Context(), bindLogKey, blog.InstanceID(instanceID), blog.BindingID(bindingID))
2625

handlers/catalog.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
const getCatalogLogKey = "getCatalog"
1313

14-
func (h *APIHandler) Catalog(w http.ResponseWriter, req *http.Request) {
14+
func (h APIHandler) Catalog(w http.ResponseWriter, req *http.Request) {
1515
logger := h.logger.Session(req.Context(), getCatalogLogKey)
1616
requestId := fmt.Sprintf("%v", req.Context().Value(middlewares.RequestIdentityKey))
1717

handlers/deprovision.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"log/slog"
66
"net/http"
77

8-
"github.com/go-chi/chi/v5"
98
"github.com/pivotal-cf/brokerapi/v11/domain"
109
"github.com/pivotal-cf/brokerapi/v11/domain/apiresponses"
1110
"github.com/pivotal-cf/brokerapi/v11/internal/blog"
@@ -15,7 +14,7 @@ import (
1514
const deprovisionLogKey = "deprovision"
1615

1716
func (h APIHandler) Deprovision(w http.ResponseWriter, req *http.Request) {
18-
instanceID := chi.URLParam(req, "instance_id")
17+
instanceID := req.PathValue("instance_id")
1918

2019
logger := h.logger.Session(req.Context(), deprovisionLogKey, blog.InstanceID(instanceID))
2120

0 commit comments

Comments
 (0)