diff --git a/rest/errors.go b/rest/errors.go index 994f5fd..2ae4c8b 100644 --- a/rest/errors.go +++ b/rest/errors.go @@ -47,29 +47,29 @@ type Error struct { // NewError returns a rest.Error from an standard error. // // If the the inputted error is recognized, the appropriate rest.Error is mapped. -func NewError(err error) *Error { +func NewError(err error) (error, int) { if Err, ok := err.(*Error); ok { - return Err + return err, Err.Code } switch err { case context.Canceled: - return ErrClientClosedRequest + return ErrClientClosedRequest, ErrClientClosedRequest.Code case context.DeadlineExceeded: - return ErrGatewayTimeout + return ErrGatewayTimeout, ErrGatewayTimeout.Code case resource.ErrNotFound: - return ErrNotFound + return ErrNotFound, ErrNotFound.Code case resource.ErrForbidden: - return ErrForbidden + return ErrForbidden, ErrForbidden.Code case resource.ErrConflict: - return ErrConflict + return ErrConflict, ErrConflict.Code case resource.ErrNotImplemented: - return ErrNotImplemented + return ErrNotImplemented, ErrNotImplemented.Code case resource.ErrNoStorage: - return &Error{501, err.Error(), nil} + return &Error{501, err.Error(), nil}, 501 case nil: - return nil + return nil, 0 default: - return &Error{520, err.Error(), nil} + return err, 520 } } diff --git a/rest/method_delete.go b/rest/method_delete.go index 82cb8e0..9bd048f 100644 --- a/rest/method_delete.go +++ b/rest/method_delete.go @@ -14,8 +14,8 @@ func listDelete(ctx context.Context, r *http.Request, route *RouteMatch) (status } total, err := route.Resource().Clear(ctx, q) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } headers = http.Header{} headers.Set("X-Total", strconv.Itoa(total)) diff --git a/rest/method_get.go b/rest/method_get.go index f4d269c..6de8e6b 100644 --- a/rest/method_get.go +++ b/rest/method_get.go @@ -36,8 +36,8 @@ func listGet(ctx context.Context, r *http.Request, route *RouteMatch) (status in list, err = rsc.Find(ctx, q) } if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } if win := q.Window; win != nil && win.Offset > 0 { list.Offset = win.Offset @@ -45,8 +45,8 @@ func listGet(ctx context.Context, r *http.Request, route *RouteMatch) (status in for _, item := range list.Items { item.Payload, err = q.Projection.Eval(ctx, item.Payload, restResource{rsc}) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } } return 200, nil, list diff --git a/rest/method_item_delete.go b/rest/method_item_delete.go index 77ebe1d..1640de2 100644 --- a/rest/method_item_delete.go +++ b/rest/method_item_delete.go @@ -16,8 +16,8 @@ func itemDelete(ctx context.Context, r *http.Request, route *RouteMatch) (status q.Window = &query.Window{Limit: 1} l, err := route.Resource().Find(ctx, q) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } if len(l.Items) == 0 { return ErrNotFound.Code, nil, ErrNotFound @@ -28,8 +28,8 @@ func itemDelete(ctx context.Context, r *http.Request, route *RouteMatch) (status return err.Code, nil, err } if err := route.Resource().Delete(ctx, original); err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } return 204, nil, nil } diff --git a/rest/method_item_get.go b/rest/method_item_get.go index 2890073..071e8d2 100644 --- a/rest/method_item_get.go +++ b/rest/method_item_get.go @@ -18,8 +18,8 @@ func itemGet(ctx context.Context, r *http.Request, route *RouteMatch) (status in q.Window = &query.Window{Limit: 1} list, err := rsrc.Find(ctx, q) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } else if len(list.Items) == 0 { return ErrNotFound.Code, nil, ErrNotFound } @@ -40,8 +40,8 @@ func itemGet(ctx context.Context, r *http.Request, route *RouteMatch) (status in } item.Payload, err = q.Projection.Eval(ctx, item.Payload, restResource{rsrc}) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } return 200, nil, item } diff --git a/rest/method_item_patch.go b/rest/method_item_patch.go index dfbc064..db5f1b4 100644 --- a/rest/method_item_patch.go +++ b/rest/method_item_patch.go @@ -48,8 +48,8 @@ func itemPatch(ctx context.Context, r *http.Request, route *RouteMatch) (status q.Window = &query.Window{Limit: 1} if l, err := rsrc.Find(ctx, q); err != nil { // If item can't be fetch, return an error. - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } else if len(l.Items) == 0 { return ErrNotFound.Code, nil, ErrNotFound } else { @@ -96,21 +96,21 @@ func itemPatch(ctx context.Context, r *http.Request, route *RouteMatch) (status } item, err := resource.NewItem(doc) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } preHookEtag := item.ETag if len(q.Projection) > 0 { projected, err := q.Projection.Eval(ctx, item.Payload, restResource{rsrc}) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } preHookEtag, err = resource.GenEtag(projected) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } } @@ -120,23 +120,23 @@ func itemPatch(ctx context.Context, r *http.Request, route *RouteMatch) (status // condition (i.e.: another thread modified the document between the Find() // and the Store()). if err = rsrc.Update(ctx, item, original); err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } postHookEtag := item.ETag // Evaluate projection so response gets the same format as read requests. item.Payload, err = q.Projection.Eval(ctx, item.Payload, restResource{rsrc}) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } if len(q.Projection) > 0 { postHookEtag, err = resource.GenEtag(item.Payload) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } } diff --git a/rest/method_item_put.go b/rest/method_item_put.go index 3f2c1d2..df5724c 100644 --- a/rest/method_item_put.go +++ b/rest/method_item_put.go @@ -27,8 +27,8 @@ func itemPut(ctx context.Context, r *http.Request, route *RouteMatch) (status in var original *resource.Item q.Window = &query.Window{Limit: 1} if l, err := rsrc.Find(ctx, q); err != nil && err != ErrNotFound { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } else if len(l.Items) == 1 { original = l.Items[0] } @@ -79,21 +79,21 @@ func itemPut(ctx context.Context, r *http.Request, route *RouteMatch) (status in } item, err := resource.NewItem(doc) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } preHookEtag := item.ETag if len(q.Projection) > 0 { projected, err := q.Projection.Eval(ctx, item.Payload, restResource{rsrc}) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } preHookEtag, err = resource.GenEtag(projected) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } } // If we have an original item, pass it to the handler so we make sure @@ -102,13 +102,13 @@ func itemPut(ctx context.Context, r *http.Request, route *RouteMatch) (status in // is provided. if original != nil { if err = rsrc.Update(ctx, item, original); err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } } else { if err = rsrc.Insert(ctx, []*resource.Item{item}); err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } } @@ -116,15 +116,15 @@ func itemPut(ctx context.Context, r *http.Request, route *RouteMatch) (status in // Evaluate projection so response gets the same format as read requests. item.Payload, err = q.Projection.Eval(ctx, item.Payload, restResource{rsrc}) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } if len(q.Projection) > 0 { postHookEtag, err = resource.GenEtag(item.Payload) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } } diff --git a/rest/method_post.go b/rest/method_post.go index 47d0c9d..fcb69d3 100644 --- a/rest/method_post.go +++ b/rest/method_post.go @@ -32,36 +32,36 @@ func listPost(ctx context.Context, r *http.Request, route *RouteMatch) (status i } item, err := resource.NewItem(doc) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } preHookEtag := item.ETag if len(q.Projection) > 0 { projected, err := q.Projection.Eval(ctx, item.Payload, restResource{rsrc}) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } preHookEtag, err = resource.GenEtag(projected) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } } // TODO: add support for batch insert if err = rsrc.Insert(ctx, []*resource.Item{item}); err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } postHookEtag := item.ETag // Evaluate projection so response gets the same format as read requests. item.Payload, err = q.Projection.Eval(ctx, item.Payload, restResource{rsrc}) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } // See https://www.subbu.org/blog/2008/10/location-vs-content-location headers = http.Header{} @@ -78,8 +78,8 @@ func listPost(ctx context.Context, r *http.Request, route *RouteMatch) (status i if len(q.Projection) > 0 { postHookEtag, err = resource.GenEtag(item.Payload) if err != nil { - e = NewError(err) - return e.Code, nil, e + e, code := NewError(err) + return code, nil, e } }