@@ -17,7 +17,6 @@ limitations under the License.
1717package api
1818
1919import (
20- "encoding/json"
2120 "fmt"
2221 "net/http"
2322 "strconv"
@@ -29,23 +28,25 @@ type HTTPError struct {
2928}
3029
3130type ErrorResponse struct {
32- Code string `json:"code"`
33- Message string `json:"message"`
31+ Code string `json:"code"`
32+ Message string `json:"message"`
33+ ValidationErrors map [string ]string `json:"validation_errors,omitempty"`
3434}
3535
3636type ErrorEnvelope struct {
3737 Error * HTTPError `json:"error"`
3838}
3939
40+ // LogError logs an error message with the request details.
4041func (a * App ) LogError (r * http.Request , err error ) {
4142 var (
4243 method = r .Method
4344 uri = r .URL .RequestURI ()
4445 )
45-
4646 a .logger .Error (err .Error (), "method" , method , "uri" , uri )
4747}
4848
49+ // LogWarn logs a warning message with the request details.
4950func (a * App ) LogWarn (r * http.Request , message string ) {
5051 var (
5152 method = r .Method
@@ -55,18 +56,7 @@ func (a *App) LogWarn(r *http.Request, message string) {
5556 a .logger .Warn (message , "method" , method , "uri" , uri )
5657}
5758
58- //nolint:unused
59- func (a * App ) badRequestResponse (w http.ResponseWriter , r * http.Request , err error ) {
60- httpError := & HTTPError {
61- StatusCode : http .StatusBadRequest ,
62- ErrorResponse : ErrorResponse {
63- Code : strconv .Itoa (http .StatusBadRequest ),
64- Message : err .Error (),
65- },
66- }
67- a .errorResponse (w , r , httpError )
68- }
69-
59+ // errorResponse writes an error response to the client.
7060func (a * App ) errorResponse (w http.ResponseWriter , r * http.Request , httpError * HTTPError ) {
7161 env := ErrorEnvelope {Error : httpError }
7262
@@ -77,6 +67,7 @@ func (a *App) errorResponse(w http.ResponseWriter, r *http.Request, httpError *H
7767 }
7868}
7969
70+ // HTTP: 500
8071func (a * App ) serverErrorResponse (w http.ResponseWriter , r * http.Request , err error ) {
8172 a .LogError (r , err )
8273
@@ -90,28 +81,19 @@ func (a *App) serverErrorResponse(w http.ResponseWriter, r *http.Request, err er
9081 a .errorResponse (w , r , httpError )
9182}
9283
93- func (a * App ) notFoundResponse (w http.ResponseWriter , r * http.Request ) {
94- httpError := & HTTPError {
95- StatusCode : http .StatusNotFound ,
96- ErrorResponse : ErrorResponse {
97- Code : strconv .Itoa (http .StatusNotFound ),
98- Message : "the requested resource could not be found" ,
99- },
100- }
101- a .errorResponse (w , r , httpError )
102- }
103-
104- func (a * App ) methodNotAllowedResponse (w http.ResponseWriter , r * http.Request ) {
84+ // HTTP: 400
85+ func (a * App ) badRequestResponse (w http.ResponseWriter , r * http.Request , err error ) {
10586 httpError := & HTTPError {
106- StatusCode : http .StatusMethodNotAllowed ,
87+ StatusCode : http .StatusBadRequest ,
10788 ErrorResponse : ErrorResponse {
108- Code : strconv .Itoa (http .StatusMethodNotAllowed ),
109- Message : fmt . Sprintf ( "the %s method is not supported for this resource" , r . Method ),
89+ Code : strconv .Itoa (http .StatusBadRequest ),
90+ Message : err . Error ( ),
11091 },
11192 }
11293 a .errorResponse (w , r , httpError )
11394}
11495
96+ // HTTP: 401
11597func (a * App ) unauthorizedResponse (w http.ResponseWriter , r * http.Request ) {
11698 httpError := & HTTPError {
11799 StatusCode : http .StatusUnauthorized ,
@@ -123,6 +105,7 @@ func (a *App) unauthorizedResponse(w http.ResponseWriter, r *http.Request) {
123105 a .errorResponse (w , r , httpError )
124106}
125107
108+ // HTTP: 403
126109func (a * App ) forbiddenResponse (w http.ResponseWriter , r * http.Request , msg string ) {
127110 a .LogWarn (r , msg )
128111
@@ -136,18 +119,51 @@ func (a *App) forbiddenResponse(w http.ResponseWriter, r *http.Request, msg stri
136119 a .errorResponse (w , r , httpError )
137120}
138121
139- //nolint:unused
140- func (a * App ) failedValidationResponse (w http.ResponseWriter , r * http.Request , errors map [string ]string ) {
141- message , err := json .Marshal (errors )
142- if err != nil {
143- message = []byte ("{}" )
122+ // HTTP: 404
123+ func (a * App ) notFoundResponse (w http.ResponseWriter , r * http.Request ) {
124+ httpError := & HTTPError {
125+ StatusCode : http .StatusNotFound ,
126+ ErrorResponse : ErrorResponse {
127+ Code : strconv .Itoa (http .StatusNotFound ),
128+ Message : "the requested resource could not be found" ,
129+ },
130+ }
131+ a .errorResponse (w , r , httpError )
132+ }
133+
134+ // HTTP: 405
135+ func (a * App ) methodNotAllowedResponse (w http.ResponseWriter , r * http.Request ) {
136+ httpError := & HTTPError {
137+ StatusCode : http .StatusMethodNotAllowed ,
138+ ErrorResponse : ErrorResponse {
139+ Code : strconv .Itoa (http .StatusMethodNotAllowed ),
140+ Message : fmt .Sprintf ("the %s method is not supported for this resource" , r .Method ),
141+ },
144142 }
143+ a .errorResponse (w , r , httpError )
144+ }
145+
146+ // HTTP:415
147+ func (a * App ) unsupportedMediaTypeResponse (w http.ResponseWriter , r * http.Request , err error ) {
148+ httpError := & HTTPError {
149+ StatusCode : http .StatusUnsupportedMediaType ,
150+ ErrorResponse : ErrorResponse {
151+ Code : strconv .Itoa (http .StatusUnsupportedMediaType ),
152+ Message : err .Error (),
153+ },
154+ }
155+ a .errorResponse (w , r , httpError )
156+ }
145157
158+ // HTTP: 422
159+ // validationErrors is a map of field reference to error message.
160+ func (a * App ) failedValidationResponse (w http.ResponseWriter , r * http.Request , validationErrors map [string ]string ) {
146161 httpError := & HTTPError {
147162 StatusCode : http .StatusUnprocessableEntity ,
148163 ErrorResponse : ErrorResponse {
149- Code : strconv .Itoa (http .StatusUnprocessableEntity ),
150- Message : string (message ),
164+ Code : strconv .Itoa (http .StatusUnprocessableEntity ),
165+ Message : "request body was not valid" ,
166+ ValidationErrors : validationErrors ,
151167 },
152168 }
153169 a .errorResponse (w , r , httpError )
0 commit comments