github.com/ashleymcnamara/buffalo@v0.8.0/errors.go (about)

     1  package buffalo
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/gobuffalo/plush"
     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 := plush.NewContextWith(data)
    75  		t, err := plush.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><%= for (k, v) in data { %>
   129  <%= inspect(k) %>: <%= inspect(v) %>
   130  <% } %></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  		<%= for (route) in routes { %>
   143  			<tr>
   144  				<td><%= route.Method %></td>
   145  				<td><%= route.Path %></td>
   146  				<td><code><%= route.HandlerName %></code></td>
   147  			</tr>
   148  		<% } %>
   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  `