An API is the exposed definition that lets other code use a service without depending on how it works inside. Think of an electrical outlet: a lamp needs a compatible plug, not knowledge of the house wiring. In Go, an interface can provide this boundary by naming the methods a service must offer. section 3.2 section 6.1
One call, two implementations
A Greeter interface declares Greet() string. Both an English greeter and a Spanish greeter satisfy it, so printGreeting can accept either without changing its calling logic. The caller relies on the method contract rather than a particular struct. section 6.2
Keep that contract focused on what callers need. A Translator interface, for example, declares Translate(word string, language string) string. A handler can receive a service satisfying that interface as a dependency. This makes it possible to isolate tests with stubs, mocks, or fakes, and to change an implementation without rewriting the handler. Once callers depend on an exposed interface, however, changing it becomes harder. section 6.0 section 6.8 section 3.2
Listing 8.10 main.go
func main() {
cfg := config.LoadConfiguration()
...
var translationService rest.Translator #1
translationService = translation.NewStaticService() #2
if cfg.LegacyEndpoint != "" {
log.Printf("creating external translation
client: %s", cfg.LegacyEndpoint)
client := translation.NewHelloClient(cfg.LegacyEndpoint) #3
translationService = translation.NewRemoteService(client) #4
}
translateHandler := rest.NewTranslateHandler(translationService) #5
}
The configuration example selects a static translation service by default or a remote one when a client URL is set, then passes the selected service to the same handler. section 8.3.2
Test the boundary through inputs and outputs rather than implementation details. That feedback helps shape an API callers can use while leaving room to replace the code behind it. section 3.2 section 6.2











































