From ed8f1e9601cabd856bb3b733d6bd54db2567f685 Mon Sep 17 00:00:00 2001 From: "Gustavo \"Guz\" L de Mello" Date: Tue, 29 Jul 2025 19:18:28 -0300 Subject: [PATCH] feat(smalltrip,problems): use Problem interface on handlers --- smalltrip/problem/http.go | 106 ++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 57 deletions(-) diff --git a/smalltrip/problem/http.go b/smalltrip/problem/http.go index fd6c35c..51403ee 100644 --- a/smalltrip/problem/http.go +++ b/smalltrip/problem/http.go @@ -8,91 +8,90 @@ import ( "strings" ) -func ProblemHandler(p any) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - h := r.Header.Get("Accept") - if strings.Contains(h, "application/xml") || strings.Contains(h, ProblemMediaTypeXML) { - ProblemHandlerXML(p).ServeHTTP(w, r) - return - } - ProblemHandlerJSON(p).ServeHTTP(w, r) - }) +type Handler func(p Problem) http.Handler + +func HandlerAll(p Problem) http.Handler { + h := HandlerContentType(map[string]Handler{ + "application/xml": HandlerXML, + ProblemMediaTypeXML: HandlerXML, + "application/json": HandlerJSON, + ProblemMediaTypeJSON: HandlerJSON, + }, HandlerJSON) + return h(p) } -func ProblemHandlerXML(p any) http.Handler { +func HandlerContentType(handlers map[string]Handler, fallback ...Handler) Handler { + return func(p Problem) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for t, h := range handlers { + if strings.Contains(r.Header.Get("Accept"), t) { + h(p).ServeHTTP(w, r) + return + } + } + if len(fallback) > 0 { + fallback[0](p).ServeHTTP(w, r) + } + }) + } +} + +func HandlerXML(p Problem) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // w.Header().Set("Content-Type", ProblemMediaTypeXML) - w.Header().Set("Content-Type", "application/xml") + w.Header().Set("Content-Type", ProblemMediaTypeXML) b, err := xml.Marshal(p) if err != nil { - ProblemHandlerJSON(p).ServeHTTP(w, r) + HandlerJSON(p).ServeHTTP(w, r) return } - w.WriteHeader(GetStatus(p)) + w.WriteHeader(p.Status()) _, err = w.Write(b) if err != nil { - ProblemHandlerJSON(p).ServeHTTP(w, r) + HandlerJSON(p).ServeHTTP(w, r) } }) } -func ProblemHandlerJSON(p any) http.Handler { +func HandlerJSON(p Problem) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", ProblemMediaTypeJSON) b, err := json.Marshal(p) if err != nil { - ProblemHandlerText(p).ServeHTTP(w, r) + HandlerText(p).ServeHTTP(w, r) return } - w.WriteHeader(GetStatus(p)) + w.WriteHeader(p.Status()) _, err = w.Write(b) if err != nil { - ProblemHandlerText(p).ServeHTTP(w, r) + HandlerText(p).ServeHTTP(w, r) } }) } -func ProblemHandlerText(p any) http.Handler { +func HandlerText(p Problem) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(GetStatus(p)) + w.WriteHeader(p.Status()) - var s string - if p, ok := p.(Problem); ok { - s = fmt.Sprintf( - "Type: %s\n"+ - "Status: %3d\n"+ - "Title: %s\n"+ - "Detail: %s\n"+ - "Instance: %s\n\n"+ - p.Type, - p.Status, - p.Title, - p.Detail, - p.Instance, - ) - } - if p, ok := p.(*Problem); ok { - s = fmt.Sprintf( - "Type: %s\n"+ - "Status: %3d\n"+ - "Title: %s\n"+ - "Detail: %s\n"+ - "Instance: %s\n\n"+ - p.Type, - p.Status, - p.Title, - p.Detail, - p.Instance, - ) - } + s := fmt.Sprintf( + "Type: %s\n"+ + "Status: %3d\n"+ + "Title: %s\n"+ + "Detail: %s\n"+ + "Instance: %s\n\n"+ + p.Type(), + p.Status(), + p.Title(), + p.Detail(), + p.Instance(), + ) _, err := w.Write(fmt.Appendf([]byte{}, "%s%+v\n\n%#v", s, p, p)) if err != nil { @@ -112,13 +111,6 @@ func ProblemHandlerText(p any) http.Handler { }) } -func GetStatus(p any) int { - if p, ok := p.(interface{ StatusCode() int }); ok { - return p.StatusCode() - } - return http.StatusInternalServerError -} - const ( ProblemMediaTypeJSON = "application/problem+json" ProblemMediaTypeXML = "application/problem+xml"