Allow overriding of the default response format (#7245)

Rather than hard-coding the default response format as HTML, allow the default to be overridden by an environment variable.  For example, given a REST API endpoint that defaults to responding in JSON, you may wish to configure the error messages to be JSON by default as well.
This commit is contained in:
Ian Roberts 2021-08-06 21:27:29 +01:00 committed by GitHub
parent 9c22ba93b2
commit e5e33051b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -62,6 +62,12 @@ const (
// ErrFilesPathVar is the name of the environment variable indicating // ErrFilesPathVar is the name of the environment variable indicating
// the location on disk of files served by the handler. // the location on disk of files served by the handler.
ErrFilesPathVar = "ERROR_FILES_PATH" ErrFilesPathVar = "ERROR_FILES_PATH"
// DefaultFormatVar is the name of the environment variable indicating
// the default error MIME type that should be returned if either the
// client does not specify an Accept header, or the Accept header provided
// cannot be mapped to a file extension.
DefaultFormatVar = "DEFAULT_RESPONSE_FORMAT"
) )
func init() { func init() {
@ -75,7 +81,12 @@ func main() {
errFilesPath = os.Getenv(ErrFilesPathVar) errFilesPath = os.Getenv(ErrFilesPathVar)
} }
http.HandleFunc("/", errorHandler(errFilesPath)) defaultFormat := "text/html"
if os.Getenv(DefaultFormatVar) != "" {
defaultFormat = os.Getenv(DefaultFormatVar)
}
http.HandleFunc("/", errorHandler(errFilesPath, defaultFormat))
http.Handle("/metrics", promhttp.Handler()) http.Handle("/metrics", promhttp.Handler())
@ -86,10 +97,16 @@ func main() {
http.ListenAndServe(fmt.Sprintf(":8080"), nil) http.ListenAndServe(fmt.Sprintf(":8080"), nil)
} }
func errorHandler(path string) func(http.ResponseWriter, *http.Request) { func errorHandler(path, defaultFormat string) func(http.ResponseWriter, *http.Request) {
defaultExts, err := mime.ExtensionsByType(defaultFormat)
if err != nil || len(defaultExts) == 0 {
panic("couldn't get file extension for default format")
}
defaultExt := defaultExts[0]
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
start := time.Now() start := time.Now()
ext := "html" ext := defaultExt
if os.Getenv("DEBUG") != "" { if os.Getenv("DEBUG") != "" {
w.Header().Set(FormatHeader, r.Header.Get(FormatHeader)) w.Header().Set(FormatHeader, r.Header.Get(FormatHeader))
@ -105,14 +122,14 @@ func errorHandler(path string) func(http.ResponseWriter, *http.Request) {
format := r.Header.Get(FormatHeader) format := r.Header.Get(FormatHeader)
if format == "" { if format == "" {
format = "text/html" format = defaultFormat
log.Printf("format not specified. Using %v", format) log.Printf("format not specified. Using %v", format)
} }
cext, err := mime.ExtensionsByType(format) cext, err := mime.ExtensionsByType(format)
if err != nil { if err != nil {
log.Printf("unexpected error reading media type extension: %v. Using %v", err, ext) log.Printf("unexpected error reading media type extension: %v. Using %v", err, ext)
format = "text/html" format = defaultFormat
} else if len(cext) == 0 { } else if len(cext) == 0 {
log.Printf("couldn't get media type extension. Using %v", ext) log.Printf("couldn't get media type extension. Using %v", ext)
} else { } else {
@ -131,6 +148,10 @@ func errorHandler(path string) func(http.ResponseWriter, *http.Request) {
if !strings.HasPrefix(ext, ".") { if !strings.HasPrefix(ext, ".") {
ext = "." + ext ext = "." + ext
} }
// special case for compatibility
if ext == ".htm" {
ext = ".html"
}
file := fmt.Sprintf("%v/%v%v", path, code, ext) file := fmt.Sprintf("%v/%v%v", path, code, ext)
f, err := os.Open(file) f, err := os.Open(file)
if err != nil { if err != nil {