github.com/mayra-cabrera/buffalo@v0.9.4-0.20170814145312-66d2e7772f11/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  // PanicHandler recovers from panics gracefully and calls
    49  // the error handling code for a 500 error.
    50  func (a *App) PanicHandler(next Handler) Handler {
    51  	return func(c Context) error {
    52  		defer func() { //catch or finally
    53  			r := recover()
    54  			var err error
    55  			if r != nil { //catch
    56  				switch t := r.(type) {
    57  				case error:
    58  					err = errors.WithStack(t)
    59  				case string:
    60  					err = errors.WithStack(errors.New(t))
    61  				default:
    62  					err = errors.New(fmt.Sprint(t))
    63  				}
    64  				eh := a.ErrorHandlers.Get(500)
    65  				eh(500, err, c)
    66  			}
    67  		}()
    68  		return next(c)
    69  	}
    70  }
    71  
    72  func defaultErrorHandler(status int, err error, c Context) error {
    73  	env := c.Value("env")
    74  	c.Logger().Error(err)
    75  	if env != nil && env.(string) == "production" {
    76  		c.Response().WriteHeader(status)
    77  		c.Response().Write([]byte(prodErrorTmpl))
    78  		return nil
    79  	}
    80  	c.Response().WriteHeader(status)
    81  
    82  	msg := fmt.Sprintf("%+v", err)
    83  	ct := c.Request().Header.Get("Content-Type")
    84  	switch strings.ToLower(ct) {
    85  	case "application/json", "text/json", "json":
    86  		err = json.NewEncoder(c.Response()).Encode(map[string]interface{}{
    87  			"error": msg,
    88  			"code":  status,
    89  		})
    90  	case "application/xml", "text/xml", "xml":
    91  	default:
    92  		err := c.Request().ParseForm()
    93  		data := map[string]interface{}{
    94  			"routes":      c.Value("routes"),
    95  			"error":       msg,
    96  			"status":      status,
    97  			"data":        c.Data(),
    98  			"params":      c.Params(),
    99  			"posted_form": c.Request().Form,
   100  			"context":     c,
   101  		}
   102  		ctx := plush.NewContextWith(data)
   103  		t, err := plush.Render(devErrorTmpl, ctx)
   104  		if err != nil {
   105  			return errors.WithStack(err)
   106  		}
   107  		res := c.Response()
   108  		_, err = res.Write([]byte(t))
   109  		return err
   110  	}
   111  	return err
   112  }
   113  
   114  var devErrorTmpl = `
   115  <html>
   116  <head>
   117    <title><%= status %> - ERROR!</title>
   118    <link rel="stylesheet" href="/assets/application.css" type="text/css" media="all">
   119    <style>
   120      .container {
   121        min-width: 320px;
   122      }
   123  
   124      body {
   125        font-family: helvetica;
   126      }
   127  
   128      table {
   129        font-size: 14px;
   130      }
   131  
   132      table.table tbody tr td {
   133        border-top: 0;
   134        padding: 10px;
   135      }
   136  
   137      pre {
   138        white-space: pre-line;
   139        margin-bottom: 10px;
   140        max-height: 275px;
   141        overflow: scroll;
   142      }
   143  
   144      header {
   145        background-color: #ed605e;
   146        padding: 10px 20px;
   147        box-sizing: border-box;
   148      }
   149  
   150      .logo img {
   151        width: 80px;
   152      }
   153  
   154      .titles h1 {
   155        font-size: 30px;
   156        font-weight: 300;
   157        color: white;
   158        margin: 24px 0;
   159      }
   160  
   161      .content h3 {
   162        color: gray;
   163        margin: 25px 0;
   164      }
   165  
   166      .centered {
   167        text-align: center;
   168      }
   169  
   170      .foot {
   171        padding: 5px 0 20px;
   172        text-align: right;
   173        text-align: right;
   174        color: #c5c5c5;
   175        font-weight: 300;
   176      }
   177  
   178      .foot a {
   179        color: #8b8b8b;
   180        text-decoration: underline;
   181      }
   182  
   183      .centered {
   184        text-align: center;
   185      }
   186  
   187      @media all and (max-width: 500px) {
   188        .titles h1 {
   189          font-size: 25px;
   190          margin: 26px 0;
   191        }
   192      }
   193  
   194      @media all and (max-width: 530px) {
   195        .titles h1 {
   196          font-size: 20px;
   197          margin: 24px 0;
   198        }
   199        .logo {
   200          padding: 0
   201        }
   202        .logo img {
   203          width: 100%;
   204          max-width: 80px;
   205        }
   206      }
   207    </style>
   208  </head>
   209  
   210  <body>
   211    <header>
   212      <div class="container">
   213        <div class="row">
   214          <div class="col-md-1 col-sm-2 col-xs-3 logo">
   215            <a href="/"><img src="https://gobuffalo.io/assets/images/logo_med.png" alt=""></a>
   216          </div>
   217          <div class="col-md-10 col-sm-6 col-xs-7 titles">
   218            <h1>
   219              <%= status %> - ERROR!
   220            </h1>
   221          </div>
   222        </div>
   223      </div>
   224    </header>
   225  
   226    <div class="container content">
   227      <div class="row">
   228        <div class="col-md-12">
   229          <h3>Error Trace</h3>
   230          <pre><%= error %></pre>
   231  
   232          <h3>Context</h3>
   233          <pre><%= inspect(context) %></pre>
   234  
   235          <h3>Parameters</h3>
   236          <pre><%= inspect(params) %></pre>
   237  
   238          <h3>Form</h3>
   239          <pre><%= inspect(posted_form) %></pre>
   240  
   241          <h3>Routes</h3>
   242          <table class="table table-striped">
   243            <thead>
   244              <tr text-align="left">
   245                <th class="centered">METHOD</th>
   246                <th>PATH</th>
   247                <th>NAME</th>
   248                <th>HANDLER</th>
   249              </tr>
   250            </thead>
   251            <tbody>
   252  
   253              <%= for (r) in routes { %>
   254                <tr>
   255                  <td class="centered">
   256                    <%= r.Method %>
   257                  </td>
   258                  <td>
   259                    <%= r.Path %>
   260                  </td>
   261                  <td>
   262                    <%= r.PathName %>
   263                  </td>
   264                  <td><code><%= r.HandlerName %></code></td>
   265                </tr>
   266              <% } %>
   267  
   268            </tbody>
   269          </table>
   270        </div>
   271      </div>
   272      <div class="foot"> <span> Powered by <a href="http://gobuffalo.io/">gobuffalo.io</a></span></div>
   273    </div>
   274  </body>
   275  </html>
   276  `
   277  var prodErrorTmpl = `
   278  <h1>We're Sorry!</h1>
   279  <p>
   280  It looks like something went wrong! Don't worry, we are aware of the problem and are looking into it.
   281  </p>
   282  <p>
   283  Sorry if this has caused you any problems. Please check back again later.
   284  </p>
   285  `