-
Notifications
You must be signed in to change notification settings - Fork 232
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
Custom http response headers #1165
base: development
Are you sure you want to change the base?
Custom http response headers #1165
Conversation
go.sum
Outdated
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.
Any specific reason to update the go.sum?
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.
None. When I ran go install golang.org/x/tools/cmd/goimports@latest
, it updated the go.sum, I can. remove it if you think it is necessary.
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.
Sure, in my opinion, go.mod & go.sum should only be updated if there are dependency update that are adding some value to the feature/enhancement/bug fix in 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.
Understood. Will remove the additions in go.sum.
pkg/gofr/handler.go
Outdated
// **Handle Custom Headers** if `result` is a `Response`. | ||
if resp, ok := result.(response.Response); ok { | ||
for key, value := range resp.Headers { | ||
w.Header().Set(key, value) |
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 we add logic to skip headers that gofr already sets, such as 'Content-type'?
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.
if resp, ok := result.(response.Response); ok {
for key, value := range resp.Headers {
if w.Header().Get(key) == "" {
w.Header().Set(key, value)
}
}
result = resp.Data
}
How about this, we'll check if a Header has been set and then set it only if it hasn't been set.
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.
Yes maybe this can help
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.
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.
@Umang01-hash @aryan-mehrotra-zs @vipul-rawat How about having a list of non overridable response headers (or response headers that can only be overridden by some special methods provided by Gofr)? So that a check can be implemented for those headers only. Intention behind is that, user deliberately wants to override those headers (such as content-type) but since Gofr is internally setting those headers, so the overall working of the framework should not break.
PS: If required, this can be done as future enhancement. For now, this PR is good.
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 would suggest if the user has provided some header which is already set by gofr that should also be over-ridden, if user doesn't set - the default which is set by gofr is used.
@ccoVeille @aryanmehrotra @Umang01-hash @shashank-zopsmart I have extracted |
case <-panicked: | ||
err = gofrHTTP.ErrorPanicRecovery{} | ||
} | ||
|
||
// **Handle Custom Headers** if `result` is a `Response`. |
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 unsure about the formatting here
In a godoc, I would have understand
Here I don't get what it brings.
I might not have raised this, but I also face a misunderstanding about the fact I don't get why there is a need to use emphasis on this
I could have understood if it was
// **Handle Custom Headers** if `result` is a `Response`. | |
// handle **Custom Headers** if `result` is a `Response`. |
But then, I would be lost anyway. Why would we need to emphasis on the fact it's custom headers, maybe you could explain
And finally, why using emphasis and not simply use quote.
// **Handle Custom Headers** if `result` is a `Response`. | |
// handle "Custom Headers" if `result` is a `Response`. |
Thanks for reading this almost useless feedback about a comment 😅😬😂
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.
Hey @ccoVeille there's no particular reason for the formatting, I am new to Go and hence was taking ChatGPT's help while writing the code, it put the comment, I didn't really think about the way the comment was formatted. I will simplify it to just read //handle custom headers if 'result' is 'Response'
if resp, ok := result.(response.Response); ok { | ||
for key, value := range resp.Headers { | ||
if w.Header().Get(key) == "" { | ||
w.Header().Set(key, value) | ||
} | ||
} | ||
result = resp.Data | ||
} |
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.
Maybe a comment explaining the reason behind this.
Here is my understanding:
There is a need to propagate the header to the caller.
Then explain existing headers are not overwritten.
For this exact reason, I would create a method in
if resp, ok := result.(response.Response); ok { | |
for key, value := range resp.Headers { | |
if w.Header().Get(key) == "" { | |
w.Header().Set(key, value) | |
} | |
} | |
result = resp.Data | |
} | |
if resp, ok := result.(response.Response); ok { | |
resp.PropagateHeaders(w) | |
result = resp.Data | |
} |
With something like this in response.Response struct
func(response.Response resp) PropagateHeaders(w *http.Response)
for key, value := range resp.Headers {
if w.Header().Get(key) != "" {
// do not overwrite existing header
continue
}
w.Header().Set(key, value)
}
}
I wrote this on a phone, there might be some errors 😅
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 think this approach is better. I just think the function should be called SetCustomHeaders
instead of PropogateHeaders
. That would explain the purpose better. Let me know what you think.
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.
@shashank-zopsmart @Umang01-hash what do you guys think, should we extract the setting of custom headers to another function or a simple if condition should suffice in the ServerHTTP func itself
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.
@rigved-telang extracting the setting of custom headers to another function is not a bad idea as it would lead to a more clear code and auto explain what the function is intended to do
if err != nil { | ||
errorLog := &ErrorLogEntry{TraceID: traceID, Error: err.Error()} | ||
h.container.Logger.Error(errorLog) | ||
} |
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.
if err != nil { | |
errorLog := &ErrorLogEntry{TraceID: traceID, Error: err.Error()} | |
h.container.Logger.Error(errorLog) | |
} | |
if err == nil { | |
return | |
} | |
errorLog := &ErrorLogEntry{TraceID: traceID, Error: err.Error()} | |
h.container.Logger.Error(errorLog) |
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'd just extracted the existing code to a new function, also isn't the logic wrong here, the error should get logged when it is not nil right?
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.
Indeed, I edited my post it should be OK now
testCases := []struct { | ||
desc string | ||
method string | ||
data interface{} |
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.
data interface{} | |
data any |
@rigved-telang can you please also resolve this linter ? |
Description:
Additional Information:
Checklist:
goimport
andgolangci-lint
.