diff --git a/http/httpErr.go b/http/httpErr.go index 982719f..6780419 100644 --- a/http/httpErr.go +++ b/http/httpErr.go @@ -1,6 +1,7 @@ package http import ( + "encoding/json" "fmt" "net/http" ) @@ -9,8 +10,63 @@ import ( // The error will have the given return code `code` // and a json encoded body with the field "id" set to `errId` // and a field "message" set to the `message` +// +// Deprecated: Use ProblemDetails or ProblemDetailsStatusOnly instead func HttpErr(w http.ResponseWriter, errId int, message string, code int) { w.WriteHeader(code) w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, "{\"id\": %d, \"message\": \"%s\"}", errId, message) } + +// Write an RFC 9457 compliant problem details response +// If details is not nil, it will be included. +// If extras is not nil, each key-value pair will be included at +// the root layer. +// Keys in extras that would overwrite the default elements will be ignored. +// Those would be "type", "status", "title" and "detail" +func ProblemDetails( + w http.ResponseWriter, + statusCode int, + errorType string, + errorTitle string, + details *string, + extras map[string]any, +) { + w.WriteHeader(statusCode) + w.Header().Add("Content-Type", "application/problem+json") + data := map[string]any{ + "type": errorType, + "status": statusCode, + "title": errorTitle, + } + if details != nil { + data["detail"] = *details + } + if extras != nil { + for k, v := range extras { + if _, ok := data[k]; ok { + // Don't overwrite default fields + continue + } + data[k] = v + } + } + enc := json.NewEncoder(w) + enc.Encode(data) +} + +// Write a simple problem details response. +// It only provides the status code, as defined in RFC 9457, section 4.2.1 +func ProblemDetailsStatusOnly(w http.ResponseWriter, statusCode int) { + w.WriteHeader(statusCode) + w.Header().Add("Content-Type", "application/problem+json") + data := map[string]any{ + "type": "about:blank", + "title": http.StatusText(statusCode), + "status": statusCode, + "reference": "RFC 9457", + } + + enc := json.NewEncoder(w) + enc.Encode(data) +}