|
|
@@ -126,6 +126,11 @@ func (c *Context) AbortWithStatus(code int) {
|
|
|
c.Abort()
|
|
|
}
|
|
|
|
|
|
+func (c *Context) AbortWithError(code int, err error) *errorMsg {
|
|
|
+ c.AbortWithStatus(code)
|
|
|
+ return c.Error(err)
|
|
|
+}
|
|
|
+
|
|
|
func (c *Context) IsAborted() bool {
|
|
|
return c.index == AbortIndex
|
|
|
}
|
|
|
@@ -134,30 +139,16 @@ func (c *Context) IsAborted() bool {
|
|
|
/********* ERROR MANAGEMENT *********/
|
|
|
/************************************/
|
|
|
|
|
|
-// Fail is the same as Abort plus an error message.
|
|
|
-// Calling `context.Fail(500, err)` is equivalent to:
|
|
|
-// ```
|
|
|
-// context.Error("Operation aborted", err)
|
|
|
-// context.AbortWithStatus(500)
|
|
|
-// ```
|
|
|
-func (c *Context) Fail(code int, err error) {
|
|
|
- c.Error(err, "Operation aborted")
|
|
|
- c.AbortWithStatus(code)
|
|
|
-}
|
|
|
-
|
|
|
-func (c *Context) ErrorTyped(err error, typ int, meta interface{}) {
|
|
|
- c.Errors = append(c.Errors, errorMsg{
|
|
|
- Error: err,
|
|
|
- Flags: typ,
|
|
|
- Meta: meta,
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
// Attaches an error to the current context. The error is pushed to a list of errors.
|
|
|
// It's a good idea to call Error for each error that occurred during the resolution of a request.
|
|
|
// A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response.
|
|
|
-func (c *Context) Error(err error, meta interface{}) {
|
|
|
- c.ErrorTyped(err, ErrorTypeExternal, meta)
|
|
|
+func (c *Context) Error(err error) *errorMsg {
|
|
|
+ newError := &errorMsg{
|
|
|
+ Error: err,
|
|
|
+ Flags: ErrorTypePrivate,
|
|
|
+ }
|
|
|
+ c.Errors = append(c.Errors, newError)
|
|
|
+ return newError
|
|
|
}
|
|
|
|
|
|
func (c *Context) LastError() error {
|
|
|
@@ -168,6 +159,35 @@ func (c *Context) LastError() error {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+/************************************/
|
|
|
+/******** METADATA MANAGEMENT********/
|
|
|
+/************************************/
|
|
|
+
|
|
|
+// Sets a new pair key/value just for the specified context.
|
|
|
+// It also lazy initializes the hashmap.
|
|
|
+func (c *Context) Set(key string, value interface{}) {
|
|
|
+ if c.Keys == nil {
|
|
|
+ c.Keys = make(map[string]interface{})
|
|
|
+ }
|
|
|
+ c.Keys[key] = value
|
|
|
+}
|
|
|
+
|
|
|
+// Get returns the value for the given key or an error if the key does not exist.
|
|
|
+func (c *Context) Get(key string) (value interface{}, exists bool) {
|
|
|
+ if c.Keys != nil {
|
|
|
+ value, exists = c.Keys[key]
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// MustGet returns the value for the given key or panics if the value doesn't exist.
|
|
|
+func (c *Context) MustGet(key string) interface{} {
|
|
|
+ if value, exists := c.Get(key); exists {
|
|
|
+ return value
|
|
|
+ }
|
|
|
+ panic("Key \"" + key + "\" does not exist")
|
|
|
+}
|
|
|
+
|
|
|
/************************************/
|
|
|
/************ INPUT DATA ************/
|
|
|
/************************************/
|
|
|
@@ -233,40 +253,29 @@ func (c *Context) postFormValue(key string) (string, bool) {
|
|
|
return "", false
|
|
|
}
|
|
|
|
|
|
-/************************************/
|
|
|
-/******** METADATA MANAGEMENT********/
|
|
|
-/************************************/
|
|
|
-
|
|
|
-// Sets a new pair key/value just for the specified context.
|
|
|
-// It also lazy initializes the hashmap.
|
|
|
-func (c *Context) Set(key string, value interface{}) {
|
|
|
- if c.Keys == nil {
|
|
|
- c.Keys = make(map[string]interface{})
|
|
|
- }
|
|
|
- c.Keys[key] = value
|
|
|
+// This function checks the Content-Type to select a binding engine automatically,
|
|
|
+// Depending the "Content-Type" header different bindings are used:
|
|
|
+// "application/json" --> JSON binding
|
|
|
+// "application/xml" --> XML binding
|
|
|
+// else --> returns an error
|
|
|
+// if Parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. It decodes the json payload into the struct specified as a pointer.Like ParseBody() but this method also writes a 400 error if the json is not valid.
|
|
|
+func (c *Context) Bind(obj interface{}) error {
|
|
|
+ b := binding.Default(c.Request.Method, c.ContentType())
|
|
|
+ return c.BindWith(obj, b)
|
|
|
}
|
|
|
|
|
|
-// Get returns the value for the given key or an error if the key does not exist.
|
|
|
-func (c *Context) Get(key string) (value interface{}, exists bool) {
|
|
|
- if c.Keys != nil {
|
|
|
- value, exists = c.Keys[key]
|
|
|
- }
|
|
|
- return
|
|
|
+func (c *Context) BindJSON(obj interface{}) error {
|
|
|
+ return c.BindWith(obj, binding.JSON)
|
|
|
}
|
|
|
|
|
|
-// MustGet returns the value for the given key or panics if the value doesn't exist.
|
|
|
-func (c *Context) MustGet(key string) interface{} {
|
|
|
- if value, exists := c.Get(key); exists {
|
|
|
- return value
|
|
|
- } else {
|
|
|
- panic("Key \"" + key + "\" does not exist")
|
|
|
+func (c *Context) BindWith(obj interface{}, b binding.Binding) error {
|
|
|
+ if err := b.Bind(c.Request, obj); err != nil {
|
|
|
+ c.AbortWithError(400, err).Type(ErrorTypeBind)
|
|
|
+ return err
|
|
|
}
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
-/************************************/
|
|
|
-/********* PARSING REQUEST **********/
|
|
|
-/************************************/
|
|
|
-
|
|
|
func (c *Context) ClientIP() string {
|
|
|
clientIP := c.Request.Header.Get("X-Real-IP")
|
|
|
if len(clientIP) > 0 {
|
|
|
@@ -284,25 +293,6 @@ func (c *Context) ContentType() string {
|
|
|
return filterFlags(c.Request.Header.Get("Content-Type"))
|
|
|
}
|
|
|
|
|
|
-// This function checks the Content-Type to select a binding engine automatically,
|
|
|
-// Depending the "Content-Type" header different bindings are used:
|
|
|
-// "application/json" --> JSON binding
|
|
|
-// "application/xml" --> XML binding
|
|
|
-// else --> returns an error
|
|
|
-// if Parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. It decodes the json payload into the struct specified as a pointer.Like ParseBody() but this method also writes a 400 error if the json is not valid.
|
|
|
-func (c *Context) Bind(obj interface{}) bool {
|
|
|
- b := binding.Default(c.Request.Method, c.ContentType())
|
|
|
- return c.BindWith(obj, b)
|
|
|
-}
|
|
|
-
|
|
|
-func (c *Context) BindWith(obj interface{}, b binding.Binding) bool {
|
|
|
- if err := b.Bind(c.Request, obj); err != nil {
|
|
|
- c.Fail(400, err)
|
|
|
- return false
|
|
|
- }
|
|
|
- return true
|
|
|
-}
|
|
|
-
|
|
|
/************************************/
|
|
|
/******** RESPONSE RENDERING ********/
|
|
|
/************************************/
|
|
|
@@ -319,8 +309,7 @@ func (c *Context) Render(code int, r render.Render) {
|
|
|
c.Writer.WriteHeader(code)
|
|
|
if err := r.Write(c.Writer); err != nil {
|
|
|
debugPrintError(err)
|
|
|
- c.ErrorTyped(err, ErrorTypeInternal, nil)
|
|
|
- c.AbortWithStatus(500)
|
|
|
+ c.AbortWithError(500, err).Type(ErrorTypeRender)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -430,7 +419,7 @@ func (c *Context) Negotiate(code int, config Negotiate) {
|
|
|
c.XML(code, data)
|
|
|
|
|
|
default:
|
|
|
- c.Fail(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server"))
|
|
|
+ c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server"))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -458,6 +447,10 @@ func (c *Context) SetAccepted(formats ...string) {
|
|
|
c.Accepted = formats
|
|
|
}
|
|
|
|
|
|
+/************************************/
|
|
|
+/******** CONTENT NEGOTIATION *******/
|
|
|
+/************************************/
|
|
|
+
|
|
|
func (c *Context) Deadline() (deadline time.Time, ok bool) {
|
|
|
return
|
|
|
}
|