github.com/lenfree/buffalo@v0.7.3-0.20170207163156-891616ea4064/errors.go (about) 1 package buffalo 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strings" 7 8 "github.com/gobuffalo/velvet" 9 "github.com/pkg/errors" 10 ) 11 12 // HTTPError a typed error returned by http Handlers and used for choosing error handlers 13 type HTTPError struct { 14 Status int `json:"status"` 15 Cause error `json:"error"` 16 } 17 18 func (h HTTPError) Error() string { 19 return h.Cause.Error() 20 } 21 22 // ErrorHandler interface for handling an error for a 23 // specific status code. 24 type ErrorHandler func(int, error, Context) error 25 26 // ErrorHandlers is used to hold a list of ErrorHandler 27 // types that can be used to handle specific status codes. 28 /* 29 a.ErrorHandlers[500] = func(status int, err error, c buffalo.Context) error { 30 res := c.Response() 31 res.WriteHeader(status) 32 res.Write([]byte(err.Error())) 33 return nil 34 } 35 */ 36 type ErrorHandlers map[int]ErrorHandler 37 38 // Get a registered ErrorHandler for this status code. If 39 // no ErrorHandler has been registered, a default one will 40 // be returned. 41 func (e ErrorHandlers) Get(status int) ErrorHandler { 42 if eh, ok := e[status]; ok { 43 return eh 44 } 45 return defaultErrorHandler 46 } 47 48 func defaultErrorHandler(status int, err error, c Context) error { 49 env := c.Value("env") 50 if env != nil && env.(string) == "production" { 51 c.Response().WriteHeader(status) 52 c.Response().Write([]byte(prodErrorTmpl)) 53 return nil 54 } 55 c.Logger().Error(err) 56 c.Response().WriteHeader(status) 57 58 msg := fmt.Sprintf("%+v", err) 59 ct := c.Request().Header.Get("Content-Type") 60 switch strings.ToLower(ct) { 61 case "application/json", "text/json", "json": 62 err = json.NewEncoder(c.Response()).Encode(map[string]interface{}{ 63 "error": msg, 64 "code": status, 65 }) 66 case "application/xml", "text/xml", "xml": 67 default: 68 data := map[string]interface{}{ 69 "routes": c.Value("routes"), 70 "error": msg, 71 "status": status, 72 "data": c.Data(), 73 } 74 ctx := velvet.NewContextWith(data) 75 t, err := velvet.Render(devErrorTmpl, ctx) 76 if err != nil { 77 return errors.WithStack(err) 78 } 79 res := c.Response() 80 res.WriteHeader(404) 81 _, err = res.Write([]byte(t)) 82 return err 83 } 84 return err 85 } 86 87 var devErrorTmpl = ` 88 <html> 89 <head> 90 <title>{{status}} - ERROR!</title> 91 <style> 92 body { 93 font-family: helvetica; 94 } 95 table { 96 width: 100%; 97 } 98 th { 99 text-align: left; 100 } 101 tr:nth-child(even) { 102 background-color: #dddddd; 103 } 104 td { 105 margin: 0px; 106 padding: 10px; 107 } 108 pre { 109 display: block; 110 padding: 9.5px; 111 margin: 0 0 10px; 112 font-size: 13px; 113 line-height: 1.42857143; 114 color: #333; 115 word-break: break-all; 116 word-wrap: break-word; 117 background-color: #f5f5f5; 118 border: 1px solid #ccc; 119 border-radius: 4px; 120 } 121 </style> 122 </head> 123 <body> 124 <h1>{{status}} - ERROR!</h1> 125 <pre>{{error}}</pre> 126 <hr> 127 <h3>Context</h3> 128 <pre>{{#each data as |k v|}} 129 {{inspect k}}: {{inspect v}} 130 {{/each}}</pre> 131 <hr> 132 <h3>Routes</h3> 133 <table id="buffalo-routes-table"> 134 <thead> 135 <tr> 136 <th>METHOD</th> 137 <th>PATH</th> 138 <th>HANDLER</th> 139 </tr> 140 </thead> 141 <tbody> 142 {{#each routes as |route|}} 143 <tr> 144 <td>{{route.Method}}</td> 145 <td>{{route.Path}}</td> 146 <td><code>{{route.HandlerName}}</code></td> 147 </tr> 148 {{/each}} 149 </tbody> 150 </table> 151 </body> 152 </html> 153 ` 154 var prodErrorTmpl = ` 155 <h1>We're Sorry!</h1> 156 <p> 157 It looks like something went wrong! Don't worry, we are aware of the problem and are looking into it. 158 </p> 159 <p> 160 Sorry if this has caused you any problems. Please check back again later. 161 </p> 162 `