Building a Flexible API
Apply the pattern.
Building a Flexible API is a free Go Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Apply the Pattern
Now assemble the full pattern: a constructor that takes required arguments plus a variadic list of options.
The Variadic Constructor
Required parameters come first; options follow as ...Option.
package main
import "fmt"
type Server struct {
Host string
Port int
}
type Option func(*Server)
func WithPort(p int) Option { return func(s *Server) { s.Port = p } }
func NewServer(host string, opts ...Option) *Server {
s := &Server{Host: host}
for _, opt := range opts {
opt(s)
}
return s
}
func main() {
s := NewServer("localhost", WithPort(8080))
fmt.Printf("%+v\n", *s)
}Calling with No Options
Because options are variadic, callers can omit them entirely and rely on whatever the constructor sets up.
package main
import "fmt"
type Server struct{ Host string; Port int }
type Option func(*Server)
func NewServer(host string, opts ...Option) *Server {
s := &Server{Host: host}
for _, o := range opts { o(s) }
return s
}
func main() {
s := NewServer("localhost")
fmt.Printf("%+v\n", *s)
}Calling with Several Options
Stack as many options as you like; each reads clearly at the call site.
package main
import "fmt"
type Server struct {
Host string
Port int
Timeout int
TLS bool
}
type Option func(*Server)
func WithPort(p int) Option { return func(s *Server) { s.Port = p } }
func WithTimeout(t int) Option { return func(s *Server) { s.Timeout = t } }
func WithTLS() Option { return func(s *Server) { s.TLS = true } }
func NewServer(host string, opts ...Option) *Server {
s := &Server{Host: host}
for _, o := range opts { o(s) }
return s
}
func main() {
s := NewServer("localhost", WithPort(9000), WithTimeout(60), WithTLS())
fmt.Printf("%+v\n", *s)
}Self-Documenting Calls
Compare NewServer("localhost", WithPort(9000), WithTLS()) to a positional call. The intent is obvious without checking the signature.
Adding Options Later
Need a new setting? Add a WithX function. Every existing call site keeps compiling untouched — true backward compatibility.
package main
import "fmt"
type Server struct{ Host string; Retries int }
type Option func(*Server)
func WithRetries(n int) Option { return func(s *Server) { s.Retries = n } }
func NewServer(host string, opts ...Option) *Server {
s := &Server{Host: host}
for _, o := range opts { o(s) }
return s
}
func main() {
fmt.Printf("%+v\n", *NewServer("h", WithRetries(5)))
}Passing Options Around
Since options are values, you can build a slice elsewhere and forward it into the constructor.
package main
import "fmt"
type Server struct{ Host string; Port int }
type Option func(*Server)
func WithPort(p int) Option { return func(s *Server) { s.Port = p } }
func NewServer(host string, opts ...Option) *Server {
s := &Server{Host: host}
for _, o := range opts { o(s) }
return s
}
func main() {
common := []Option{WithPort(443)}
s := NewServer("api", common...)
fmt.Printf("%+v\n", *s)
}Options as a Public API
Export the Option type and WithX functions so library users configure your type without touching its internals.
Keeping Fields Private
Config fields can stay unexported; options are the only sanctioned way to set them, protecting invariants.
Where the Pattern Shines
- Library constructors with many optional knobs
- APIs that must stay stable as they grow
- Clients, servers, loggers, builders
Standard Library Echoes
You will see this style across the Go ecosystem (gRPC, many drivers). Recognizing it makes those APIs feel familiar.
Quick Check
Test your flexible API knowledge.
Recap
You built a flexible API with functional options.
- Required args first, then
...Option - Loop over options applying each
- Callers pass zero or many, reading clearly
- Add options later without breaking callers
Frequently asked questions
Is the “Building a Flexible API” lesson free?
Yes — the full text of “Building a Flexible API” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.
What will I learn in “Building a Flexible API”?
Apply the pattern. You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Go Academy?
No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Building a Flexible API” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Go Academy lesson?
Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The Problem with Many Params
- Option Functions
- Building a Flexible API
- Defaults and Validation