Skip to content

Commit a8a24e7

Browse files
authored
take optional Opts for modifying the http server (#219)
* take optional Opts for modifying the http server * move to have separate constructor * use the params * comment to make Keiko happy
1 parent f6b214e commit a8a24e7

File tree

2 files changed

+101
-26
lines changed

2 files changed

+101
-26
lines changed

server/options.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package server
2+
3+
import (
4+
"crypto/tls"
5+
"fmt"
6+
"net/http"
7+
"time"
8+
)
9+
10+
// Opt will allow modification of the http server
11+
type Opt func(s *http.Server)
12+
13+
// WithWriteTimeout will override the server's write timeout
14+
func WithWriteTimeout(dur time.Duration) Opt {
15+
return func(s *http.Server) {
16+
s.WriteTimeout = dur
17+
}
18+
}
19+
20+
// WithReadTimeout will override the server's read timeout
21+
func WithReadTimeout(dur time.Duration) Opt {
22+
return func(s *http.Server) {
23+
s.ReadTimeout = dur
24+
}
25+
}
26+
27+
// WithTLS will use the provided TLS configuration
28+
func WithTLS(cfg *tls.Config) Opt {
29+
return func(s *http.Server) {
30+
s.TLSConfig = cfg
31+
}
32+
}
33+
34+
// WithAddress will set the address field on the server
35+
func WithAddress(addr string) Opt {
36+
return func(s *http.Server) {
37+
s.Addr = addr
38+
}
39+
}
40+
41+
// WithHostAndPort will use them in the form host:port as the address field on the server
42+
func WithHostAndPort(host string, port int) Opt {
43+
return WithAddress(fmt.Sprintf("%s:%d", host, port))
44+
}

server/server.go

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package server
22

33
import (
44
"context"
5-
"fmt"
65
"net/http"
76
"net/http/httptest"
87
"os"
@@ -16,6 +15,11 @@ import (
1615
"github.com/sirupsen/logrus"
1716
)
1817

18+
const (
19+
defaultPort = 9090
20+
defaultHealthPath = "/health"
21+
)
22+
1923
// Server handles the setup and shutdown of the http server
2024
// for an API
2125
type Server struct {
@@ -52,44 +56,33 @@ type HealthChecker interface {
5256
Healthy(w http.ResponseWriter, r *http.Request) error
5357
}
5458

55-
func New(log logrus.FieldLogger, config Config, api APIDefinition) (*Server, error) {
56-
var healthHandler router.APIHandler
57-
if checker, ok := api.(HealthChecker); ok {
58-
healthHandler = checker.Healthy
59+
// NewOpts will create the server with many defaults. You can use the opts to override them.
60+
// the one major default you can't change by this is the health path. This is set to /health
61+
// and be enabled.
62+
func NewOpts(log logrus.FieldLogger, api APIDefinition, opts ...Opt) (*Server, error) {
63+
defaultOpts := []Opt{
64+
WithHostAndPort("", defaultPort),
5965
}
6066

61-
r := router.New(
62-
log,
63-
router.OptHealthCheck(config.HealthPath, healthHandler),
64-
router.OptEnableTracing(api.Info().Name),
65-
router.OptVersionHeader(api.Info().Name, api.Info().Version),
66-
router.OptRecoverer(),
67-
)
68-
69-
if err := api.Start(r); err != nil {
70-
return nil, errors.Wrap(err, "Failed to start API")
71-
}
67+
return buildServer(log, api, append(defaultOpts, opts...), defaultHealthPath)
68+
}
7269

73-
s := Server{
74-
log: log.WithField("component", "server"),
75-
svr: &http.Server{
76-
Addr: fmt.Sprintf("%s:%d", config.Host, config.Port),
77-
Handler: r,
78-
},
79-
api: api,
80-
done: make(chan bool),
70+
// New will build a server with the defaults in place
71+
func New(log logrus.FieldLogger, config Config, api APIDefinition) (*Server, error) {
72+
opts := []Opt{
73+
WithHostAndPort(config.Host, config.Port),
8174
}
8275

8376
if config.TLS.Enabled {
8477
tcfg, err := config.TLS.TLSConfig()
8578
if err != nil {
8679
return nil, errors.Wrap(err, "Failed to build TLS config")
8780
}
88-
s.svr.TLSConfig = tcfg
8981
log.Info("TLS enabled")
82+
opts = append(opts, WithTLS(tcfg))
9083
}
9184

92-
return &s, nil
85+
return buildServer(log, api, opts, config.HealthPath)
9386
}
9487

9588
func (s *Server) Shutdown(to time.Duration) error {
@@ -172,3 +165,41 @@ func APIFunc(start func(router.Router) error, stop func(), info APIInfo) APIDefi
172165
info: info,
173166
}
174167
}
168+
169+
func buildRouter(log logrus.FieldLogger, api APIDefinition, healthPath string) router.Router {
170+
var healthHandler router.APIHandler
171+
if checker, ok := api.(HealthChecker); ok {
172+
healthHandler = checker.Healthy
173+
}
174+
175+
r := router.New(
176+
log,
177+
router.OptHealthCheck(healthPath, healthHandler),
178+
router.OptEnableTracing(api.Info().Name),
179+
router.OptVersionHeader(api.Info().Name, api.Info().Version),
180+
router.OptRecoverer(),
181+
)
182+
183+
return r
184+
}
185+
186+
func buildServer(log logrus.FieldLogger, api APIDefinition, opts []Opt, healthPath string) (*Server, error) {
187+
r := buildRouter(log, api, healthPath)
188+
189+
if err := api.Start(r); err != nil {
190+
return nil, errors.Wrap(err, "Failed to start API")
191+
}
192+
193+
svr := new(http.Server)
194+
for _, o := range opts {
195+
o(svr)
196+
}
197+
svr.Handler = r
198+
s := Server{
199+
log: log.WithField("component", "server"),
200+
svr: svr,
201+
api: api,
202+
done: make(chan bool),
203+
}
204+
return &s, nil
205+
}

0 commit comments

Comments
 (0)