diff --git a/errors.go b/errors.go index 691a209d0b34f8332a5f04b83656ba1864b3913d..97639d873f99d01450e95eb268a73817b1003eb9 100644 --- a/errors.go +++ b/errors.go @@ -100,6 +100,8 @@ func (v *validationError) JSON() []byte { return data } +// orNil solves the problem with nil-wrapping interfaces by returning +// an unwrapped nil if the validationError is nil. func (v *validationError) orNil() error { if v == nil { return nil diff --git a/server/server.go b/server/server.go index 3cb32aaf7e6eee7ed86e14e9e6a7c854e8d473c2..8e0e7c7780541c053149ea8b12b9afa6b1c4f181 100644 --- a/server/server.go +++ b/server/server.go @@ -70,6 +70,10 @@ func New(service *as.AccountService, backend as.Backend) *APIServer { var emptyResponse struct{} +type jsonError interface { + JSON() []byte +} + func (s *APIServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Create a new empty request object based on the request // path, then decode the HTTP request JSON body onto it. @@ -85,7 +89,15 @@ func (s *APIServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { resp, err := s.service.Handle(req.Context(), r) if err != nil { - http.Error(w, err.Error(), errToStatus(err)) + // Handle structured errors, serve a JSON response. + status := errToStatus(err) + if jerr, ok := err.(jsonError); ok { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(status) + w.Write(jerr.JSON()) // nolint + } else { + http.Error(w, err.Error(), status) + } } else { // Don't send nulls, send empty dicts instead. if resp == nil {