github.com/uber/kraken@v0.1.4/utils/handler/handler.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package handler 15 16 import ( 17 "fmt" 18 "net/http" 19 20 "github.com/uber/kraken/utils/log" 21 ) 22 23 // Error defines an HTTP handler error which encapsulates status and headers 24 // to be set in the HTTP response. 25 type Error struct { 26 status int 27 header http.Header 28 msg string 29 } 30 31 // Errorf creates a new Error with Printf-style formatting. Defaults to 500 error. 32 func Errorf(format string, args ...interface{}) *Error { 33 return &Error{ 34 status: http.StatusInternalServerError, 35 header: http.Header{}, 36 msg: fmt.Sprintf(format, args...), 37 } 38 } 39 40 // ErrorStatus creates an empty message error with status s. 41 func ErrorStatus(s int) *Error { 42 return Errorf("").Status(s) 43 } 44 45 // Status sets a custom status on e. 46 func (e *Error) Status(s int) *Error { 47 e.status = s 48 return e 49 } 50 51 // Header adds a custom header to e. 52 func (e *Error) Header(k, v string) *Error { 53 e.header.Add(k, v) 54 return e 55 } 56 57 // GetStatus returns the error status. 58 func (e *Error) GetStatus() int { 59 return e.status 60 } 61 62 func (e *Error) Error() string { 63 if e.msg == "" { 64 return fmt.Sprintf("server error %d", e.status) 65 } 66 return fmt.Sprintf("server error %d: %s", e.status, e.msg) 67 } 68 69 // ErrHandler defines an HTTP handler which returns an error. 70 type ErrHandler func(http.ResponseWriter, *http.Request) error 71 72 // Wrap converts an ErrHandler into an http.HandlerFunc by handling the error 73 // returned by h. 74 func Wrap(h ErrHandler) http.HandlerFunc { 75 return func(w http.ResponseWriter, r *http.Request) { 76 var status int 77 var errMsg string 78 if err := h(w, r); err != nil { 79 switch e := err.(type) { 80 case *Error: 81 for k, vs := range e.header { 82 for _, v := range vs { 83 w.Header().Add(k, v) 84 } 85 } 86 status = e.status 87 errMsg = e.msg 88 default: 89 status = http.StatusInternalServerError 90 errMsg = e.Error() 91 } 92 w.WriteHeader(status) 93 w.Write([]byte(errMsg)) 94 } else { 95 status = http.StatusOK 96 } 97 if status >= 400 && status != 404 { 98 log.Infof("%d %s %s %s", status, r.Method, r.URL.Path, errMsg) 99 } 100 } 101 }