-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change error responses from plain text to JSON #4845
Conversation
6e99e83
to
da5fd0d
Compare
@@ -236,6 +236,7 @@ func writeError(w http.ResponseWriter, err error) { | |||
err = errRequestEntityTooLarge | |||
} | |||
} | |||
w.Header().Set("Content-Type", "text/plain; charset=UTF-8") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hhmm, I wonder if it's better for us to instead format the error as JSON so that at least we have some consistency.
What made you take this approach vs that one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good point, I've also considered that, and thinking about it again, it's clearly the more consistent approach. I guess, people do not really depend on the response body being kept the same.
Also, I think there are still other occurrences where the response body is plain text. Will update the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't that break the API? I'm not sure how strict we are there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few thoughts:
- the API is inconsistent
- if we're changing anything it's technically breaking the API
- I'd rather break it in the direction of consistency 😝
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with consistency even by breaking the API response. But should definitely add it in our docs/sources/upgrading/_index.md
. (/cc @chaudum )
pkg/util/server/error.go
Outdated
|
||
func JSONError(w http.ResponseWriter, code int, message string, args ...interface{}) { | ||
w.WriteHeader(code) | ||
w.Header().Set("Content-Type", "application/json; charset=UTF8") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
w.Header().Set("Content-Type", "application/json; charset=UTF8") | |
w.Header().Set("Content-Type", "application/json; charset=UTF-8") |
22f0a78
to
693fda0
Compare
The API returned errors in plain text where the error message was the response body. However, the content type header was set to `application/json`. To make the API responses consistent, errors are now returned as JSON as well. ``` { "message": string, "status": string, "code": int } ``` Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
d23c854
to
75d4199
Compare
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs portion of the PR looks good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial review; have a couple questions
docs/sources/upgrading/_index.md
Outdated
} | ||
``` | ||
|
||
"404 Not Found" errors still return responses with content type `text/plain`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we special-case 404s? This is going to make writing Loki clients complex.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
404 errors are handled differently than errors that occur in our handlers. However, it should be possible to override the NotFoundHandler of the router.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you look into that please? We should really try have consistency across the board if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was actually pretty easy to achieve: 4820322
@@ -39,21 +39,21 @@ func (dm *DeleteRequestHandler) AddDeleteRequestHandler(w http.ResponseWriter, r | |||
ctx := r.Context() | |||
userID, err := tenant.TenantID(ctx) | |||
if err != nil { | |||
http.Error(w, err.Error(), http.StatusBadRequest) | |||
serverutil.JSONError(w, http.StatusBadRequest, err.Error()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not too familiar with how HTTP errors are handled, but are they not all handled pkg/util/server/error.go -> WriteError
? If we use http.Error
here does it kill the request and write this error directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WriteError
handles generic errors as Internal Server Error
. Therefore we bypass WriteError
and call JSONError
directly, so we can specify a status code and an error message.
http.Error
sets the status code, content type header (text/plain
) and writes the response body. Usually you want to return thereafter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK thanks for that. I was looking for a way that we could somehow add middleware to catch these http.Error
calls, but they write directly to the http.ResponseWriter
:(
I would've loved to have stuck with idiomatic gorilla/mux & net/http, but it seems we don't have a good layer of indirection here.
What you've got here looks like a good solution 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An option to catch and resolve errors in a middleware would be, to write an occurring error to the request context and check for it in the middleware handler. I don't think that is very idiomatic, though. Writing the error to the response writer seems to be the common way.
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 great work @chaudum
One tiny nit then I'll merge
pkg/util/server/error.go
Outdated
@@ -34,9 +34,13 @@ type ErrorResponseBody struct { | |||
Message string `json:"message"` | |||
} | |||
|
|||
func NotFoundHandler(w http.ResponseWriter, r *http.Request) { | |||
JSONError(w, 404, "page not found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<nit>
JSONError(w, 404, "page not found") | |
JSONError(w, 404, "not found") |
</nit>
We don't really work with "pages" - let's not confuse the operator
Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
@darrenjaneczek Could this potentially affect the Loki datasource plugin / GEL plugin? |
…nt type from plain text to JSON is a breaking change of the API and we should wait to do this at a major release. Signed-off-by: Ed Welch <edward.welch@grafana.com>
…5772) * This reverts the changes from #4845, unfortunately changing the content type from plain text to JSON is a breaking change of the API and we should wait to do this at a major release. Signed-off-by: Ed Welch <edward.welch@grafana.com> * fix tests which were updated after initial change. Signed-off-by: Ed Welch <edward.welch@grafana.com>
…5772) * This reverts the changes from #4845, unfortunately changing the content type from plain text to JSON is a breaking change of the API and we should wait to do this at a major release. Signed-off-by: Ed Welch <edward.welch@grafana.com> * fix tests which were updated after initial change. Signed-off-by: Ed Welch <edward.welch@grafana.com> (cherry picked from commit c158b2c)
…5772) (#5774) * This reverts the changes from #4845, unfortunately changing the content type from plain text to JSON is a breaking change of the API and we should wait to do this at a major release. Signed-off-by: Ed Welch <edward.welch@grafana.com> * fix tests which were updated after initial change. Signed-off-by: Ed Welch <edward.welch@grafana.com> (cherry picked from commit c158b2c) Co-authored-by: Ed Welch <edward.welch@grafana.com>
… API (grafana#5772) (grafana#5774) * This reverts the changes from grafana#4845, unfortunately changing the content type from plain text to JSON is a breaking change of the API and we should wait to do this at a major release. Signed-off-by: Ed Welch <edward.welch@grafana.com> * fix tests which were updated after initial change. Signed-off-by: Ed Welch <edward.welch@grafana.com> (cherry picked from commit c158b2c) Co-authored-by: Ed Welch <edward.welch@grafana.com>
Signed-off-by: Christian Haudum christian.haudum@gmail.com
What this PR does / why we need it:
Set correct content-type header when returning error responses with plain text body.
Which issue(s) this PR fixes:
Fixes #4844
Checklist
CHANGELOG.md
about the changes.