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  }