An anti-corruption layer keeps a backend’s data structures and calling conventions out of the rest of an application. In an HTML server backed by a habits service, the `client` package isolates the generated gRPC structures, while the `habit` package defines data that can pass between internal packages. section 11.1.3
Listing 11.14 list.go: Client can list the habits
// ListHabits lists the habits available.
func (hc *HabitsClient) ListHabits(ctx context.Context,
t time.Time) ([]habit.Habit, error) { #1
resp, err := hc.cli.ListHabits(ctx,
&api.ListHabitsRequest{}) #2
if err != nil {...}
list := make([]habit.Habit, len(resp.Habits))
for i, h := range resp.Habits {
list[i] = habit.Habit{ #3
ID: //...
}
}
return list, nil
}
The wrapping client calls the generated gRPC client, then starts constructing a slice of internal `habit.Habit` values from the response. Callers receive domain data rather than Protobuf response types. section 11.1.3
Keep the boundary testable by passing the generated `api.HabitsClient` interface into the wrapper’s constructor. A handler can depend on an even smaller interface that returns `[]habit.Habit`; it need not know how the backend call works. Tests can substitute a mock client and check both returned habits and backend errors. section 11.1.3
Listing 11.20 server.go: Using the client dependency
// HabitsClient is the dependency towards the Habits client.
//go:generate minimock -s "_mock.go" -o "mocks" #1
type HabitsClient interface {
ListHabits(ctx context.Context) ([]habit.Habit, error)
}
// Server serves all the HTML routes on this service.
type Server struct {
client HabitsClient #2
lgr Logger
}
// New builds a new server.
func New(cli HabitsClient, lgr Logger) *Server { #3
return &Server{
client: cli,
lgr: lgr,
}
}
// Router returns an HTTP handler that listens to all the proper paths.
func (s *Server) Router() http.Handler {...}
The HTTP server’s dependency names the one operation it needs, `ListHabits`, in terms of internal habit values. This keeps generated gRPC types out of the handler interface. section 11.1.3
The same boundary can serve another API: a service reads external data and inserts it into its domain. The practical takeaway is to put translation and external calls in one place, then let the application work with its own model. section 1.3.1 section 11.1.3


