--- theme: default layout: center class: text-center fonts: sans: "CaskaydiaCove Nerd Font Mono" --- # A Trick for Designing
Friendly APIs in Go --- layout: center --- # The Optional Configuration Problem ```go // No defaults? // What is sensible? // What does 'true' do? // What is '30'? srv := NewServer("localhost", 8080, 30, true) ``` --- layout: center --- # "We need to add a TLS parameter." ```go func NewServer(host string, port int, timeout int) *Server { // ... } ``` --- layout: center --- # "Just use a struct" ```go srv := NewServer(Config{ Host: "localhost", Port: 0, }) ``` --- layout: center class: text-center --- # "Nah bro, use functional options." --- layout: center --- # 1. Define the option ```go type Server struct { host string port int } // Option is a function that modifies the Server type Option func(*Server) ``` --- layout: center --- # 2. Create closures ```go // WithPort captures the 'port' value func WithPort(port int) Option { // It returns a closure return func(s *Server) { s.port = port } } func WithHost(h string) Option { return func(s *Server) { s.host = h } } ``` --- layout: center class: text-center --- # 3. Get variadic
```go func NewServer(host string, port int) *Server { return &Server{ host: host, port: port, } } ```
```go func NewServer(opts ...Option) *Server { s := &Server{ host: "localhost", port: 80, } for _, opt := range opts { opt(s) } return s } ```
--- layout: center --- # Almost as good as C# ```go srv := NewServer( WithHost("api.google.com"), WithPort(9090), WithTimeout(30 * time.Second), ) ``` --- layout: center class: text-center --- # Extensibility? We got you.
Support TLS... ```go func WithTLS(cert, key string) Option { return func(s *Server) { s.tls = true s.cert = cert s.key = key } } ```
Breaks nothing. ```go srv := NewServer(WithPort(8080)) srv2 := NewServer( WithPort(8080), WithTLS("cert.pem", "key.pem"), ) ```
--- layout: center class: text-center --- # So why use this pattern?
Defaults are easy (just call New)
Usage is self-documenting
New options don't break old code
--- layout: center class: text-center --- # Go forth and build friendly APIs!