I noticed whilst writing some RESTful endpoints in Lambda, I had three models, and the handlers, were all identical. They take a request, fetch some data from a repository, and return the data as a response. The only thing which differed in each handler function, was the model instance. So I was thinking of ways of passing in the type and re-using the same functionality for marshalling the response into JSON etc.
If I have a pattern such as this:
type Handler struct {
model interface{}
repository
}
func (h *Handler) Fetch(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
model := h.model
if err := h.repository.Fetch(id, &model); err != nil {
return ErrResponse(err, http.StatusInternalServerError)
}
return Response(map[string]interface{}{
"resource": model,
}, http.StatusOK)
}
Then calling this:
repository := NewRepository(tableName, connection)
handler := &helpers.Handler{repository, new(models.Client)}
I'm re-assigning model := h.model
so that the struct itself doesn't become 'stateful', otherwise I'd have to worry about locking to ensure its thread safe. So I figured I could just re-assign it in the scope of the handler to avoid that.
This pattern seems to work okay, but I wondered if there were any potential downsides or pitfalls?