Merge pull request #11540 from influxdata/http_error_cleanup

Http error cleanup
pull/11361/head
kelwang 2019-01-25 10:47:44 -08:00 committed by GitHub
commit d90e635958
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 539 additions and 375 deletions

View File

@ -10,15 +10,16 @@ import (
// Some error code constant, ideally we want define common platform codes here
// projects on use platform's error, should have their own central place like this.
const (
EInternal = "internal error"
ENotFound = "not found"
EConflict = "conflict" // action cannot be performed
EInvalid = "invalid" // validation failed
EEmptyValue = "empty value"
EUnavailable = "unavailable"
EForbidden = "forbidden"
EUnauthorized = "unauthorized"
EMethodNotAllowed = "method not allowed"
EInternal = "internal error"
ENotFound = "not found"
EConflict = "conflict" // action cannot be performed
EInvalid = "invalid" // validation failed
EUnprocessableEntity = "unprocessable entity" // data type is correct, but out of range
EEmptyValue = "empty value"
EUnavailable = "unavailable"
EForbidden = "forbidden"
EUnauthorized = "unauthorized"
EMethodNotAllowed = "method not allowed"
)
// Error is the error struct of platform.

View File

@ -611,7 +611,7 @@ func (s *AuthorizationService) FindAuthorizationByID(ctx context.Context, id pla
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -665,7 +665,7 @@ func (s *AuthorizationService) FindAuthorizations(ctx context.Context, filter pl
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, 0, err
}
@ -722,7 +722,7 @@ func (s *AuthorizationService) CreateAuthorization(ctx context.Context, a *platf
defer resp.Body.Close()
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -767,7 +767,7 @@ func (s *AuthorizationService) SetAuthorizationStatus(ctx context.Context, id pl
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -794,7 +794,7 @@ func (s *AuthorizationService) DeleteAuthorization(ctx context.Context, id platf
}
defer resp.Body.Close()
return CheckError(resp, true)
return CheckError(resp)
}
func authorizationIDPath(id platform.ID) string {

View File

@ -13,9 +13,7 @@ import (
platform "github.com/influxdata/influxdb"
pcontext "github.com/influxdata/influxdb/context"
"github.com/influxdata/influxdb/inmem"
"github.com/influxdata/influxdb/kit/errors"
"github.com/influxdata/influxdb/mock"
platformtesting "github.com/influxdata/influxdb/testing"
"github.com/julienschmidt/httprouter"
)
@ -522,7 +520,10 @@ func TestService_handlePostAuthorization(t *testing.T) {
UserService: &mock.UserService{
FindUserByIDFn: func(ctx context.Context, id platform.ID) (*platform.User, error) {
if !id.Valid() {
return nil, errors.New("invalid user ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "invalid user id",
}
}
return &platform.User{
ID: id,
@ -533,7 +534,10 @@ func TestService_handlePostAuthorization(t *testing.T) {
OrganizationService: &mock.OrganizationService{
FindOrganizationByIDF: func(ctx context.Context, id platform.ID) (*platform.Organization, error) {
if !id.Valid() {
return nil, errors.New("invalid org ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "invalid org ID",
}
}
return &platform.Organization{
ID: id,

View File

@ -11,7 +11,6 @@ import (
"time"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/kit/errors"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
@ -102,7 +101,10 @@ func (b *bucket) toPlatform() (*platform.Bucket, error) {
if len(b.RetentionRules) > 0 {
d = time.Duration(b.RetentionRules[0].EverySeconds) * time.Second
if d < time.Second {
return nil, errors.InvalidDataf("expiration seconds must be greater than or equal to one second")
return nil, &platform.Error{
Code: platform.EUnprocessableEntity,
Msg: "expiration seconds must be greater than or equal to one second",
}
}
}
@ -156,7 +158,10 @@ func (b *bucketUpdate) toPlatform() (*platform.BucketUpdate, error) {
if len(b.RetentionRules) > 0 {
d = time.Duration(b.RetentionRules[0].EverySeconds) * time.Second
if d < time.Second {
return nil, errors.InvalidDataf("expiration seconds must be greater than or equal to one second")
return nil, &platform.Error{
Code: platform.EUnprocessableEntity,
Msg: "expiration seconds must be greater than or equal to one second",
}
}
}
@ -324,7 +329,10 @@ func decodeGetBucketRequest(ctx context.Context, r *http.Request) (*getBucketReq
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -364,7 +372,10 @@ func decodeDeleteBucketRequest(ctx context.Context, r *http.Request) (*deleteBuc
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -480,17 +491,26 @@ func decodePatchBucketRequest(ctx context.Context, r *http.Request) (*patchBucke
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
if err := i.DecodeFromString(id); err != nil {
return nil, err
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: err.Error(),
}
}
bu := &bucketUpdate{}
if err := json.NewDecoder(r.Body).Decode(bu); err != nil {
return nil, err
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: err.Error(),
}
}
upd, err := bu.toPlatform()
@ -538,7 +558,7 @@ func (s *BucketService) FindBucketByID(ctx context.Context, id platform.ID) (*pl
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -561,7 +581,6 @@ func (s *BucketService) FindBucket(ctx context.Context, filter platform.BucketFi
Code: platform.ENotFound,
Op: s.OpPrefix + platform.OpFindBucket,
Msg: "bucket not found",
Err: ErrNotFound,
}
}
@ -613,7 +632,7 @@ func (s *BucketService) FindBuckets(ctx context.Context, filter platform.BucketF
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, 0, err
}
@ -664,7 +683,7 @@ func (s *BucketService) CreateBucket(ctx context.Context, b *platform.Bucket) er
defer resp.Body.Close()
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -711,7 +730,7 @@ func (s *BucketService) UpdateBucket(ctx context.Context, id platform.ID, upd pl
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -742,7 +761,7 @@ func (s *BucketService) DeleteBucket(ctx context.Context, id platform.ID) error
}
defer resp.Body.Close()
return CheckError(resp, true)
return CheckError(resp)
}
func bucketIDPath(id platform.ID) string {
@ -780,7 +799,10 @@ func decodeGetBucketLogRequest(ctx context.Context, r *http.Request) (*getBucket
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID

View File

@ -414,8 +414,7 @@ func TestService_handlePostBucket(t *testing.T) {
body, _ := ioutil.ReadAll(res.Body)
if res.StatusCode != tt.wants.statusCode {
msg := res.Header.Get(ErrorHeader)
t.Errorf("%q. handlePostBucket() = %v, want %v: %s", tt.name, res.StatusCode, tt.wants.statusCode, msg)
t.Errorf("%q. handlePostBucket() = %v, want %v", tt.name, res.StatusCode, tt.wants.statusCode)
}
if tt.wants.contentType != "" && content != tt.wants.contentType {
t.Errorf("%q. handlePostBucket() = %v, want %v", tt.name, content, tt.wants.contentType)

View File

@ -11,7 +11,6 @@ import (
"strconv"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/kit/errors"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
@ -246,7 +245,11 @@ func (h *DashboardHandler) handleGetDashboards(w http.ResponseWriter, r *http.Re
mappings, _, err := h.UserResourceMappingService.FindUserResourceMappings(ctx, filter)
if err != nil {
EncodeError(ctx, errors.InternalErrorf("Error loading dashboard owners: %v", err), w)
EncodeError(ctx, &platform.Error{
Code: platform.EInternal,
Msg: "Error loading dashboard owners",
Err: err,
}, w)
return
}
@ -349,7 +352,11 @@ func (h *DashboardHandler) handlePostDashboard(w http.ResponseWriter, r *http.Re
return
}
if err := h.DashboardService.CreateDashboard(ctx, req.Dashboard); err != nil {
EncodeError(ctx, errors.InternalErrorf("Error loading dashboards: %v", err), w)
EncodeError(ctx, &platform.Error{
Code: platform.EInternal,
Msg: "Error loading dashboards",
Err: err,
}, w)
return
}
@ -409,7 +416,10 @@ func decodeGetDashboardRequest(ctx context.Context, r *http.Request) (*getDashbo
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -453,7 +463,10 @@ func decodeGetDashboardLogRequest(ctx context.Context, r *http.Request) (*getDas
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -513,7 +526,10 @@ func decodeDeleteDashboardRequest(ctx context.Context, r *http.Request) (*delete
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -562,14 +578,20 @@ func decodePatchDashboardRequest(ctx context.Context, r *http.Request) (*patchDa
req := &patchDashboardRequest{}
upd := platform.DashboardUpdate{}
if err := json.NewDecoder(r.Body).Decode(&upd); err != nil {
return nil, errors.MalformedDataf(err.Error())
return nil, &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
req.Upd = upd
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
if err := i.DecodeFromString(id); err != nil {
@ -579,7 +601,10 @@ func decodePatchDashboardRequest(ctx context.Context, r *http.Request) (*patchDa
req.DashboardID = i
if err := req.Valid(); err != nil {
return nil, errors.MalformedDataf(err.Error())
return nil, &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
return req, nil
@ -588,7 +613,10 @@ func decodePatchDashboardRequest(ctx context.Context, r *http.Request) (*patchDa
// Valid validates that the dashboard ID is non zero valued and update has expected values set.
func (r *patchDashboardRequest) Valid() error {
if !r.DashboardID.Valid() {
return fmt.Errorf("missing dashboard ID")
return &platform.Error{
Code: platform.EInvalid,
Msg: "missing dashboard ID",
}
}
if pe := r.Upd.Valid(); pe != nil {
@ -609,7 +637,10 @@ func decodePostDashboardCellRequest(ctx context.Context, r *http.Request) (*post
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
if err := req.dashboardID.DecodeFromString(id); err != nil {
return nil, err
@ -662,7 +693,10 @@ func decodePutDashboardCellRequest(ctx context.Context, r *http.Request) (*putDa
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
if err := req.dashboardID.DecodeFromString(id); err != nil {
return nil, err
@ -708,7 +742,10 @@ func decodeDeleteDashboardCellRequest(ctx context.Context, r *http.Request) (*de
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
if err := req.dashboardID.DecodeFromString(id); err != nil {
return nil, err
@ -716,7 +753,10 @@ func decodeDeleteDashboardCellRequest(ctx context.Context, r *http.Request) (*de
cellID := params.ByName("cellID")
if cellID == "" {
return nil, errors.InvalidDataf("url missing cellID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing cellID",
}
}
if err := req.cellID.DecodeFromString(cellID); err != nil {
return nil, err
@ -943,7 +983,7 @@ func (s *DashboardService) FindDashboardByID(ctx context.Context, id platform.ID
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -997,7 +1037,7 @@ func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.D
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return dashboards, 0, err
}
@ -1038,7 +1078,7 @@ func (s *DashboardService) CreateDashboard(ctx context.Context, d *platform.Dash
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -1079,7 +1119,7 @@ func (s *DashboardService) UpdateDashboard(ctx context.Context, id platform.ID,
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -1114,7 +1154,7 @@ func (s *DashboardService) DeleteDashboard(ctx context.Context, id platform.ID)
}
defer resp.Body.Close()
return CheckError(resp, true)
return CheckError(resp)
}
// AddDashboardCell adds a cell to a dashboard.
@ -1145,7 +1185,7 @@ func (s *DashboardService) AddDashboardCell(ctx context.Context, id platform.ID,
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -1173,7 +1213,7 @@ func (s *DashboardService) RemoveDashboardCell(ctx context.Context, dashboardID,
}
defer resp.Body.Close()
return CheckError(resp, true)
return CheckError(resp)
}
// UpdateDashboardCell replaces the dashboard cell with the provided ID.
@ -1212,7 +1252,7 @@ func (s *DashboardService) UpdateDashboardCell(ctx context.Context, dashboardID,
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -1247,7 +1287,7 @@ func (s *DashboardService) GetDashboardCellView(ctx context.Context, dashboardID
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -1287,7 +1327,7 @@ func (s *DashboardService) UpdateDashboardCellView(ctx context.Context, dashboar
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -1328,7 +1368,7 @@ func (s *DashboardService) ReplaceDashboardCells(ctx context.Context, id platfor
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}

View File

@ -792,40 +792,40 @@ func TestService_handlePatchDashboard(t *testing.T) {
statusCode: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: `
{
"id": "020f755c3c082000",
"orgID": "0000000000000001",
"name": "example",
"description": "",
"labels": [],
"meta": {
"createdAt": "2012-11-10T23:00:00Z",
"updatedAt": "2012-11-11T01:00:00Z"
},
"cells": [
{
"id": "da7aba5e5d81e550",
"x": 1,
"y": 2,
"w": 3,
"h": 4,
"links": {
"self": "/api/v2/dashboards/020f755c3c082000/cells/da7aba5e5d81e550",
"view": "/api/v2/dashboards/020f755c3c082000/cells/da7aba5e5d81e550/view"
}
}
],
"links": {
"self": "/api/v2/dashboards/020f755c3c082000",
"org": "/api/v2/orgs/0000000000000001",
"members": "/api/v2/dashboards/020f755c3c082000/members",
"owners": "/api/v2/dashboards/020f755c3c082000/owners",
"log": "/api/v2/dashboards/020f755c3c082000/log",
"cells": "/api/v2/dashboards/020f755c3c082000/cells",
"labels": "/api/v2/dashboards/020f755c3c082000/labels"
}
}
`,
{
"id": "020f755c3c082000",
"orgID": "0000000000000001",
"name": "example",
"description": "",
"labels": [],
"meta": {
"createdAt": "2012-11-10T23:00:00Z",
"updatedAt": "2012-11-11T01:00:00Z"
},
"cells": [
{
"id": "da7aba5e5d81e550",
"x": 1,
"y": 2,
"w": 3,
"h": 4,
"links": {
"self": "/api/v2/dashboards/020f755c3c082000/cells/da7aba5e5d81e550",
"view": "/api/v2/dashboards/020f755c3c082000/cells/da7aba5e5d81e550/view"
}
}
],
"links": {
"self": "/api/v2/dashboards/020f755c3c082000",
"org": "/api/v2/orgs/0000000000000001",
"members": "/api/v2/dashboards/020f755c3c082000/members",
"owners": "/api/v2/dashboards/020f755c3c082000/owners",
"log": "/api/v2/dashboards/020f755c3c082000/log",
"cells": "/api/v2/dashboards/020f755c3c082000/cells",
"labels": "/api/v2/dashboards/020f755c3c082000/labels"
}
}
`,
},
},
{

View File

@ -5,11 +5,14 @@ import (
"strconv"
"time"
"github.com/influxdata/influxdb/kit/errors"
"github.com/influxdata/influxdb"
)
// ErrInvalidDuration is returned when parsing a malformatted duration.
var ErrInvalidDuration = errors.New("invalid duration", errors.MalformedData)
var ErrInvalidDuration = &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "invalid duration",
}
// ParseDuration parses a time duration from a string.
// This is needed instead of time.ParseDuration because this will support

View File

@ -5,27 +5,15 @@ import (
"encoding/json"
"fmt"
"net/http"
"strconv"
platform "github.com/influxdata/influxdb"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/pkg/errors"
)
const (
// PlatformErrorCodeHeader shows the error code of platform error.
PlatformErrorCodeHeader = "X-Platform-Error-Code"
// ErrorHeader is the standard location for influx errors to be reported.
ErrorHeader = "X-Influx-Error"
// ReferenceHeader is the header for the reference error reference code.
ReferenceHeader = "X-Influx-Reference"
errorHeaderMaxLength = 256
)
// ErrNotFound is returned when a request for a resource returns no results.
var ErrNotFound = errors.New("no results found")
// AuthzError is returned for authorization errors. When this error type is returned,
// the user can be presented with a generic "authorization failed" error, but
// the system can log the underlying AuthzError() so that operators have insight
@ -36,11 +24,8 @@ type AuthzError interface {
}
// CheckErrorStatus for status and any error in the response.
func CheckErrorStatus(code int, res *http.Response, isPlatformError ...bool) error {
func CheckErrorStatus(code int, res *http.Response) error {
err := CheckError(res)
if len(isPlatformError) > 0 && isPlatformError[0] {
err = CheckError(res, true)
}
if err != nil {
return err
}
@ -58,8 +43,7 @@ func CheckErrorStatus(code int, res *http.Response, isPlatformError ...bool) err
// be determined in that way, it will create a generic error message.
//
// If there is no error, then this returns nil.
// THIS IS TEMPORARY. ADD AN OPTIONAL isPlatformError, TO DECODE platform.Error
func CheckError(resp *http.Response, isPlatformError ...bool) (err error) {
func CheckError(resp *http.Response) (err error) {
switch resp.StatusCode / 100 {
case 4, 5:
// We will attempt to parse this error outside of this block.
@ -67,101 +51,52 @@ func CheckError(resp *http.Response, isPlatformError ...bool) (err error) {
return nil
default:
// TODO(jsternberg): Figure out what to do here?
return kerrors.InternalErrorf("unexpected status code: %d %s", resp.StatusCode, resp.Status)
}
if len(isPlatformError) > 0 && isPlatformError[0] {
pe := new(platform.Error)
parseErr := json.NewDecoder(resp.Body).Decode(pe)
if parseErr != nil {
return parseErr
}
err = pe
return err
}
// Attempt to read the X-Influx-Error header with the message.
if errMsg := resp.Header.Get(ErrorHeader); errMsg != "" {
// Parse the reference number as an integer. If we cannot parse it,
// return the error message by itself.
ref, err := strconv.Atoi(resp.Header.Get(ReferenceHeader))
if err != nil {
// We cannot parse the reference number so just use internal.
ref = kerrors.InternalError
}
return &kerrors.Error{
Reference: ref,
Code: resp.StatusCode,
Err: errMsg,
return &platform.Error{
Code: platform.EInternal,
Msg: fmt.Sprintf("unexpected status code: %d %s", resp.StatusCode, resp.Status),
}
}
// There is no influx error so we need to report that we have some kind
// of error from somewhere.
// TODO(jsternberg): Try to make this more advance by reading the response
// and either decoding a possible json message or just reading the text itself.
// This might be good enough though.
msg := "unknown server error"
if resp.StatusCode/100 == 4 {
msg = "client error"
pe := new(platform.Error)
parseErr := json.NewDecoder(resp.Body).Decode(pe)
if parseErr != nil {
return parseErr
}
return errors.Wrap(errors.New(resp.Status), msg)
return pe
}
// EncodeError encodes err with the appropriate status code and format,
// sets the X-Influx-Error and X-Influx-Reference headers on the response,
// sets the X-Platform-Error-Code headers on the response.
// We're no longer using X-Influx-Error and X-Influx-Reference.
// and sets the response status to the corresponding status code.
func EncodeError(ctx context.Context, err error, w http.ResponseWriter) {
if err == nil {
return
}
if pe, ok := err.(*platform.Error); ok {
code := platform.ErrorCode(pe)
httpCode, ok := statusCodePlatformError[code]
if !ok {
httpCode = http.StatusBadRequest
}
w.Header().Set(PlatformErrorCodeHeader, code)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(httpCode)
b, _ := json.Marshal(&platform.Error{
Code: code,
Op: platform.ErrorOp(pe),
Msg: platform.ErrorMessage(pe),
Err: pe.Err,
})
_, _ = w.Write(b)
return
}
e, ok := err.(kerrors.Error)
code := platform.ErrorCode(err)
httpCode, ok := statusCodePlatformError[code]
if !ok {
e = kerrors.Error{
Reference: kerrors.InternalError,
Err: err.Error(),
httpCode = http.StatusBadRequest
}
w.Header().Set(PlatformErrorCodeHeader, code)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(httpCode)
var e error
if pe, ok := err.(*platform.Error); ok {
e = &platform.Error{
Code: code,
Op: platform.ErrorOp(err),
Msg: platform.ErrorMessage(err),
Err: pe.Err,
}
} else {
e = &platform.Error{
Code: platform.EInternal,
Err: err,
}
}
encodeKError(e, w)
}
func encodeKError(e kerrors.Error, w http.ResponseWriter) {
if e.Reference == 0 {
e.Reference = kerrors.InternalError
}
if len(e.Err) > errorHeaderMaxLength {
e.Err = e.Err[0:errorHeaderMaxLength]
}
code := statusCode(e)
w.Header().Set(ErrorHeader, e.Err)
w.Header().Set(ReferenceHeader, strconv.Itoa(e.Reference))
w.WriteHeader(code)
}
// ForbiddenError encodes error with a forbidden status code.
func ForbiddenError(ctx context.Context, err error, w http.ResponseWriter) {
EncodeError(ctx, &platform.Error{
Code: platform.EForbidden,
Err: err,
}, w)
b, _ := json.Marshal(e)
_, _ = w.Write(b)
}
// UnauthorizedError encodes a error message and status code for unauthorized access.
@ -172,36 +107,16 @@ func UnauthorizedError(ctx context.Context, w http.ResponseWriter) {
}, w)
}
// statusCode returns the http status code for an error.
func statusCode(e kerrors.Error) int {
if e.Code > 0 {
return e.Code
}
switch e.Reference {
case kerrors.InternalError:
return http.StatusInternalServerError
case kerrors.InvalidData:
return http.StatusUnprocessableEntity
case kerrors.MalformedData:
return http.StatusBadRequest
case kerrors.Forbidden:
return http.StatusForbidden
case kerrors.NotFound:
return http.StatusNotFound
default:
return http.StatusInternalServerError
}
}
// statusCodePlatformError is the map convert platform.Error to error
var statusCodePlatformError = map[string]int{
platform.EInternal: http.StatusInternalServerError,
platform.EInvalid: http.StatusBadRequest,
platform.EEmptyValue: http.StatusBadRequest,
platform.EConflict: http.StatusUnprocessableEntity,
platform.ENotFound: http.StatusNotFound,
platform.EUnavailable: http.StatusServiceUnavailable,
platform.EForbidden: http.StatusForbidden,
platform.EUnauthorized: http.StatusUnauthorized,
platform.EMethodNotAllowed: http.StatusMethodNotAllowed,
platform.EInternal: http.StatusInternalServerError,
platform.EInvalid: http.StatusBadRequest,
platform.EUnprocessableEntity: http.StatusUnprocessableEntity,
platform.EEmptyValue: http.StatusBadRequest,
platform.EConflict: http.StatusUnprocessableEntity,
platform.ENotFound: http.StatusNotFound,
platform.EUnavailable: http.StatusServiceUnavailable,
platform.EForbidden: http.StatusForbidden,
platform.EUnauthorized: http.StatusUnauthorized,
platform.EMethodNotAllowed: http.StatusMethodNotAllowed,
}

View File

@ -4,9 +4,9 @@ import (
"context"
"fmt"
"net/http/httptest"
"strings"
"testing"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/http"
)
@ -34,17 +34,18 @@ func TestEncodeErrorWithError(t *testing.T) {
t.Errorf("expected status code 500, got: %d", w.Code)
}
errHeader := w.Header().Get("X-Influx-Error")
if errHeader != err.Error() {
t.Errorf("expected X-Influx-Error: %s, got: %s", err.Error(), errHeader)
errHeader := w.Header().Get("X-Platform-Error-Code")
if errHeader != influxdb.EInternal {
t.Errorf("expected X-Platform-Error-Code: %s, got: %s", influxdb.EInternal, errHeader)
}
errMsg := strings.Repeat("x", 512)
err = fmt.Errorf(errMsg)
expected := errMsg[:256]
http.EncodeError(ctx, err, w)
errHeader = w.Header().Get("X-Influx-Error")
if errHeader != expected {
t.Errorf("Expected a truncated X-Influx-Error header content: %s, got: %s", expected, errHeader)
expected := &influxdb.Error{
Code: influxdb.EInternal,
Err: err,
}
pe := http.CheckError(w.Result())
if pe.(*influxdb.Error).Err.Error() != expected.Err.Error() {
t.Errorf("errors encode err: got %s", w.Body.String())
}
}

View File

@ -133,12 +133,12 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}).Observe(duration.Seconds())
if h.Logger != nil {
errField := zap.Skip()
if errStr := w.Header().Get(ErrorHeader); errStr != "" {
if errStr := w.Header().Get(PlatformErrorCodeHeader); errStr != "" {
errField = zap.Error(errors.New(errStr))
}
errReferenceField := zap.Skip()
if errReference := w.Header().Get(ReferenceHeader); errReference != "" {
errReferenceField = zap.String("reference", errReference)
if errReference := w.Header().Get(PlatformErrorCodeHeader); errReference != "" {
errReferenceField = zap.String("error_code", PlatformErrorCodeHeader)
}
h.Logger.Debug("Request",

View File

@ -9,8 +9,6 @@ import (
"path"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/kit/errors"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
@ -188,7 +186,10 @@ func decodeDeleteLabelRequest(ctx context.Context, r *http.Request) (*deleteLabe
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -233,7 +234,10 @@ func decodePatchLabelRequest(ctx context.Context, r *http.Request) (*patchLabelR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -326,7 +330,10 @@ func decodeGetLabelsRequest(ctx context.Context, r *http.Request) (*getLabelsReq
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -383,7 +390,10 @@ func decodePostLabelMappingRequest(ctx context.Context, r *http.Request) (*postL
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var rid platform.ID
@ -497,7 +507,7 @@ func (s *LabelService) FindLabelByID(ctx context.Context, id platform.ID) (*plat
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -575,7 +585,7 @@ func (s *LabelService) CreateLabel(ctx context.Context, l *platform.Label) error
defer resp.Body.Close()
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -657,7 +667,7 @@ func (s *LabelService) UpdateLabel(ctx context.Context, id platform.ID, upd plat
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -688,7 +698,7 @@ func (s *LabelService) DeleteLabel(ctx context.Context, id platform.ID) error {
}
defer resp.Body.Close()
return CheckError(resp, true)
return CheckError(resp)
}
func (s *LabelService) DeleteLabelMapping(ctx context.Context, m *platform.LabelMapping) error {

View File

@ -9,7 +9,6 @@ import (
"path"
platform "github.com/influxdata/influxdb"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
@ -115,7 +114,11 @@ func (h *MacroHandler) handleGetMacros(w http.ResponseWriter, r *http.Request) {
macros, err := h.MacroService.FindMacros(ctx, req.filter, req.opts)
if err != nil {
EncodeError(ctx, kerrors.InternalErrorf("could not read macros: %v", err), w)
EncodeError(ctx, &platform.Error{
Code: platform.EInternal,
Msg: "could not read macros",
Err: err,
}, w)
return
}
@ -130,14 +133,17 @@ func requestMacroID(ctx context.Context) (platform.ID, error) {
params := httprouter.ParamsFromContext(ctx)
urlID := params.ByName("id")
if urlID == "" {
return platform.InvalidID(), kerrors.InvalidDataf("url missing id")
return platform.InvalidID(), &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
id, err := platform.IDFromString(urlID)
if err != nil {
return platform.InvalidID(), &platform.Error{
Code: platform.EInvalid,
Err: err,
Msg: err.Error(),
}
}
@ -221,7 +227,10 @@ func decodePostMacroRequest(ctx context.Context, r *http.Request) (*postMacroReq
err := json.NewDecoder(r.Body).Decode(m)
if err != nil {
return nil, kerrors.MalformedDataf(err.Error())
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: err.Error(),
}
}
req := &postMacroRequest{
@ -229,7 +238,10 @@ func decodePostMacroRequest(ctx context.Context, r *http.Request) (*postMacroReq
}
if err := req.Valid(); err != nil {
return nil, kerrors.InvalidDataf(err.Error())
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: err.Error(),
}
}
return req, nil
@ -271,7 +283,10 @@ func decodePatchMacroRequest(ctx context.Context, r *http.Request) (*patchMacroR
err := json.NewDecoder(r.Body).Decode(u)
if err != nil {
return nil, kerrors.MalformedDataf(err.Error())
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: err.Error(),
}
}
id, err := requestMacroID(ctx)
@ -285,7 +300,10 @@ func decodePatchMacroRequest(ctx context.Context, r *http.Request) (*patchMacroR
}
if err := req.Valid(); err != nil {
return nil, kerrors.InvalidDataf(err.Error())
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: err.Error(),
}
}
return req, nil
@ -326,7 +344,10 @@ func decodePutMacroRequest(ctx context.Context, r *http.Request) (*putMacroReque
err := json.NewDecoder(r.Body).Decode(m)
if err != nil {
return nil, kerrors.MalformedDataf(err.Error())
return nil, &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
req := &putMacroRequest{
@ -334,7 +355,10 @@ func decodePutMacroRequest(ctx context.Context, r *http.Request) (*putMacroReque
}
if err := req.Valid(); err != nil {
return nil, kerrors.InvalidDataf(err.Error())
return nil, &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
return req, nil
@ -387,7 +411,7 @@ func (s *MacroService) FindMacroByID(ctx context.Context, id platform.ID) (*plat
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -435,7 +459,7 @@ func (s *MacroService) FindMacros(ctx context.Context, filter platform.MacroFilt
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -451,7 +475,10 @@ func (s *MacroService) FindMacros(ctx context.Context, filter platform.MacroFilt
// CreateMacro creates a new macro and assigns it an platform.ID
func (s *MacroService) CreateMacro(ctx context.Context, m *platform.Macro) error {
if err := m.Valid(); err != nil {
return kerrors.InvalidDataf(err.Error())
return &platform.Error{
Code: platform.EInvalid,
Err: err,
}
}
url, err := newURL(s.Addr, macroPath)
@ -480,7 +507,7 @@ func (s *MacroService) CreateMacro(ctx context.Context, m *platform.Macro) error
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -515,7 +542,7 @@ func (s *MacroService) UpdateMacro(ctx context.Context, id platform.ID, update *
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -555,7 +582,7 @@ func (s *MacroService) ReplaceMacro(ctx context.Context, macro *platform.Macro)
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -586,7 +613,7 @@ func (s *MacroService) DeleteMacro(ctx context.Context, id platform.ID) error {
}
defer resp.Body.Close()
return CheckError(resp, true)
return CheckError(resp)
}
func macroIDPath(id platform.ID) string {

View File

@ -3,6 +3,7 @@ package http
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
@ -10,7 +11,6 @@ import (
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/inmem"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/influxdata/influxdb/mock"
platformtesting "github.com/influxdata/influxdb/testing"
"github.com/julienschmidt/httprouter"
@ -214,14 +214,17 @@ func TestMacroService_handleGetMacro(t *testing.T) {
fields: fields{
&mock.MacroService{
FindMacroByIDF: func(ctx context.Context, id platform.ID) (*platform.Macro, error) {
return nil, kerrors.Errorf(kerrors.NotFound, "macro with ID %v not found", id)
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: fmt.Sprintf("macro with ID %v not found", id),
}
},
},
},
wants: wants{
statusCode: 404,
contentType: "",
body: ``,
contentType: "application/json; charset=utf-8",
body: `{"code":"not found","message":"macro with ID 75650d0a636f6d70 not found"}`,
},
},
{
@ -239,7 +242,7 @@ func TestMacroService_handleGetMacro(t *testing.T) {
wants: wants{
statusCode: 400,
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"An internal error has occurred.","error":"id must have a length of 16 bytes"}`,
body: `{"code":"invalid","message":"id must have a length of 16 bytes"}`,
},
},
}
@ -350,9 +353,9 @@ func TestMacroService_handlePostMacro(t *testing.T) {
macro: `{"data": "nonsense"}`,
},
wants: wants{
statusCode: 422,
contentType: "",
body: "",
statusCode: 400,
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"missing macro name"}`,
},
},
{
@ -370,8 +373,8 @@ func TestMacroService_handlePostMacro(t *testing.T) {
},
wants: wants{
statusCode: 400,
contentType: "",
body: "",
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"invalid character 'h' looking for beginning of value"}`,
},
},
}
@ -462,9 +465,9 @@ func TestMacroService_handlePatchMacro(t *testing.T) {
update: `{}`,
},
wants: wants{
statusCode: 422,
contentType: "",
body: ``,
statusCode: 400,
contentType: "application/json; charset=utf-8",
body: `{"code":"invalid","message":"no fields supplied in update"}`,
},
},
}
@ -543,7 +546,10 @@ func TestMacroService_handleDeleteMacro(t *testing.T) {
fields: fields{
&mock.MacroService{
DeleteMacroF: func(ctx context.Context, id platform.ID) error {
return kerrors.Errorf(kerrors.NotFound, "macro with ID %v not found", id)
return &platform.Error{
Code: platform.ENotFound,
Msg: fmt.Sprintf("macro with ID %v not found", id),
}
},
},
},

View File

@ -167,7 +167,7 @@ func (s *SetupService) Generate(ctx context.Context, or *platform.OnboardingRequ
}
defer resp.Body.Close()
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}

View File

@ -10,7 +10,6 @@ import (
"strconv"
platform "github.com/influxdata/influxdb"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
@ -211,7 +210,10 @@ func decodeGetOrgRequest(ctx context.Context, r *http.Request) (*getOrgRequest,
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -297,7 +299,10 @@ func decodeDeleteOrganizationRequest(ctx context.Context, r *http.Request) (*del
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -342,7 +347,10 @@ func decodePatchOrgRequest(ctx context.Context, r *http.Request) (*patchOrgReque
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -392,7 +400,10 @@ func decodeGetSecretsRequest(ctx context.Context, r *http.Request) (*getSecretsR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -432,7 +443,10 @@ func decodePatchSecretsRequest(ctx context.Context, r *http.Request) (*patchSecr
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -477,7 +491,10 @@ func decodeDeleteSecretsRequest(ctx context.Context, r *http.Request) (*deleteSe
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -571,7 +588,7 @@ func (s *OrganizationService) FindOrganizations(ctx context.Context, filter plat
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, 0, err
}
@ -588,7 +605,10 @@ func (s *OrganizationService) FindOrganizations(ctx context.Context, filter plat
// CreateOrganization creates an organization.
func (s *OrganizationService) CreateOrganization(ctx context.Context, o *platform.Organization) error {
if o.Name == "" {
return kerrors.InvalidDataf("organization name is required")
return &platform.Error{
Code: platform.EInvalid,
Msg: "organization name is required",
}
}
url, err := newURL(s.Addr, organizationPath)
@ -618,7 +638,7 @@ func (s *OrganizationService) CreateOrganization(ctx context.Context, o *platfor
defer resp.Body.Close()
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -657,7 +677,7 @@ func (s *OrganizationService) UpdateOrganization(ctx context.Context, id platfor
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -689,7 +709,7 @@ func (s *OrganizationService) DeleteOrganization(ctx context.Context, id platfor
}
defer resp.Body.Close()
return CheckErrorStatus(http.StatusNoContent, resp, true)
return CheckErrorStatus(http.StatusNoContent, resp)
}
func organizationIDPath(id platform.ID) string {
@ -727,7 +747,10 @@ func decodeGetOrganizationLogRequest(ctx context.Context, r *http.Request) (*get
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID

View File

@ -2,12 +2,12 @@ package http
import (
"context"
"fmt"
"net/http"
"net/url"
"strconv"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/kit/errors"
)
// decodeFindOptions returns a FindOptions decoded from http request.
@ -31,7 +31,10 @@ func decodeFindOptions(ctx context.Context, r *http.Request) (*platform.FindOpti
}
if l < 1 || l > platform.MaxPageSize {
return nil, errors.InvalidDataf("limit must be between 1 and %d", platform.MaxPageSize)
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: fmt.Sprintf("limit must be between 1 and %d", platform.MaxPageSize),
}
}
opts.Limit = l

View File

@ -3,6 +3,7 @@ package http
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"mime"
@ -21,7 +22,6 @@ import (
"github.com/influxdata/flux/semantic"
"github.com/influxdata/flux/values"
platform "github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/kit/errors"
"github.com/influxdata/influxdb/query"
"github.com/influxdata/influxql"
)

View File

@ -17,7 +17,6 @@ import (
"github.com/influxdata/flux/parser"
platform "github.com/influxdata/influxdb"
pcontext "github.com/influxdata/influxdb/context"
"github.com/influxdata/influxdb/kit/errors"
"github.com/influxdata/influxdb/query"
"github.com/julienschmidt/httprouter"
"github.com/prometheus/client_golang/prometheus"
@ -107,14 +106,22 @@ func (h *FluxHandler) postFluxAST(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&request)
if err != nil {
EncodeError(ctx, errors.MalformedDataf("invalid json: %v", err), w)
EncodeError(ctx, &platform.Error{
Code: platform.EInvalid,
Msg: "invalid json",
Err: err,
}, w)
return
}
pkg := parser.ParseSource(request.Query)
if ast.Check(pkg) > 0 {
err := ast.GetError(pkg)
EncodeError(ctx, errors.InvalidDataf("invalid AST: %v", err), w)
EncodeError(ctx, &platform.Error{
Code: platform.EInvalid,
Msg: "invalid AST",
Err: err,
}, w)
return
}
@ -134,7 +141,11 @@ func (h *FluxHandler) postQueryAnalyze(w http.ResponseWriter, r *http.Request) {
var req QueryRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
EncodeError(ctx, errors.MalformedDataf("invalid json: %v", err), w)
EncodeError(ctx, &platform.Error{
Code: platform.EInvalid,
Msg: "invalid json",
Err: err,
}, w)
return
}
@ -160,13 +171,21 @@ func (h *FluxHandler) postFluxSpec(w http.ResponseWriter, r *http.Request) {
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
EncodeError(ctx, errors.MalformedDataf("invalid json: %v", err), w)
EncodeError(ctx, &platform.Error{
Code: platform.EInvalid,
Msg: "invalid json",
Err: err,
}, w)
return
}
spec, err := flux.Compile(ctx, req.Query, h.Now())
if err != nil {
EncodeError(ctx, errors.InvalidDataf("invalid spec: %v", err), w)
EncodeError(ctx, &platform.Error{
Code: platform.EUnprocessableEntity,
Msg: "invalid spec",
Err: err,
}, w)
return
}
@ -298,7 +317,7 @@ func (s *FluxService) Query(ctx context.Context, w io.Writer, r *query.ProxyRequ
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return 0, err
}
if err := CheckError(resp); err != nil {
@ -357,7 +376,7 @@ func (s *FluxQueryService) Query(ctx context.Context, r *query.Request) (flux.Re
}
// Can't defer resp.Body.Close here because the CSV decoder depends on reading from resp.Body after this function returns.
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}

View File

@ -210,6 +210,7 @@ func TestFluxHandler_postFluxAST(t *testing.T) {
name: "error from bad json",
w: httptest.NewRecorder(),
r: httptest.NewRequest("POST", "/api/v2/query/ast", bytes.NewBufferString(`error!`)),
want: `{"code":"invalid","message":"invalid json","error":"invalid character 'e' looking for beginning of value"}`,
status: http.StatusBadRequest,
},
}
@ -249,6 +250,7 @@ func TestFluxHandler_postFluxSpec(t *testing.T) {
name: "error from bad json",
w: httptest.NewRecorder(),
r: httptest.NewRequest("POST", "/api/v2/query/spec", bytes.NewBufferString(`error!`)),
want: `{"code":"invalid","message":"invalid json","error":"invalid character 'e' looking for beginning of value"}`,
status: http.StatusBadRequest,
},
{
@ -256,6 +258,7 @@ func TestFluxHandler_postFluxSpec(t *testing.T) {
w: httptest.NewRecorder(),
r: httptest.NewRequest("POST", "/api/v2/query/spec", bytes.NewBufferString(`{"query": "from()"}`)),
now: func() time.Time { return time.Unix(0, 0).UTC() },
want: `{"code":"unprocessable entity","message":"invalid spec","error":"error calling function \"from\": must specify one of bucket or bucketID"}`,
status: http.StatusUnprocessableEntity,
},
{

View File

@ -171,7 +171,7 @@ func (s *QueryService) Query(ctx context.Context, req *query.Request) (flux.Resu
if err != nil {
return nil, err
}
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}

View File

@ -277,7 +277,7 @@ func (s *ScraperService) ListTargets(ctx context.Context) ([]influxdb.ScraperTar
return nil, err
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -328,7 +328,7 @@ func (s *ScraperService) UpdateTarget(ctx context.Context, update *influxdb.Scra
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
var targetResp targetResponse
@ -383,7 +383,7 @@ func (s *ScraperService) AddTarget(ctx context.Context, target *influxdb.Scraper
defer resp.Body.Close()
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -415,7 +415,7 @@ func (s *ScraperService) RemoveTarget(ctx context.Context, id influxdb.ID) error
}
defer resp.Body.Close()
return CheckErrorStatus(http.StatusNoContent, resp, true)
return CheckErrorStatus(http.StatusNoContent, resp)
}
// GetTargetByID returns a single target by ID.
@ -438,7 +438,7 @@ func (s *ScraperService) GetTargetByID(ctx context.Context, id influxdb.ID) (*in
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}

View File

@ -15,7 +15,6 @@ import (
platform "github.com/influxdata/influxdb"
pcontext "github.com/influxdata/influxdb/context"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/influxdata/influxdb/task/backend"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
@ -279,7 +278,10 @@ func decodeGetTasksRequest(ctx context.Context, r *http.Request) (*getTasksReque
return nil, err
}
if lim < 1 || lim > platform.TaskMaxPageSize {
return nil, kerrors.InvalidDataf("limit must be between 1 and %d", platform.TaskMaxPageSize)
return nil, &platform.Error{
Code: platform.EUnprocessableEntity,
Msg: fmt.Sprintf("limit must be between 1 and %d", platform.TaskMaxPageSize),
}
}
req.filter.Limit = lim
} else {
@ -427,7 +429,10 @@ func decodeGetTaskRequest(ctx context.Context, r *http.Request) (*getTaskRequest
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -499,7 +504,10 @@ func decodeUpdateTaskRequest(ctx context.Context, r *http.Request) (*updateTaskR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("you must provide a task ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a task ID",
}
}
var i platform.ID
@ -552,7 +560,10 @@ func decodeDeleteTaskRequest(ctx context.Context, r *http.Request) (*deleteTaskR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("you must provide a task ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a task ID",
}
}
var i platform.ID
@ -603,7 +614,10 @@ func decodeGetLogsRequest(ctx context.Context, r *http.Request, orgs platform.Or
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("you must provide a task ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a task ID",
}
}
req := &getLogsRequest{}
@ -680,7 +694,10 @@ func decodeGetRunsRequest(ctx context.Context, r *http.Request, orgs platform.Or
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("you must provide a task ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a task ID",
}
}
req := &getRunsRequest{}
@ -722,7 +739,10 @@ func decodeGetRunsRequest(ctx context.Context, r *http.Request, orgs platform.Or
}
if i < 1 || i > 100 {
return nil, kerrors.InvalidDataf("limit must be between 1 and 100")
return nil, &platform.Error{
Code: platform.EUnprocessableEntity,
Msg: "limit must be between 1 and 100",
}
}
req.filter.Limit = i
@ -747,7 +767,10 @@ func decodeGetRunsRequest(ctx context.Context, r *http.Request, orgs platform.Or
}
if at != "" && bt != "" && !beforeTime.After(afterTime) {
return nil, kerrors.InvalidDataf("beforeTime must be later than afterTime")
return nil, &platform.Error{
Code: platform.EUnprocessableEntity,
Msg: "beforeTime must be later than afterTime",
}
}
return req, nil
@ -769,9 +792,12 @@ func (h *TaskHandler) handleForceRun(w http.ResponseWriter, r *http.Request) {
run, err := h.TaskService.ForceRun(ctx, req.TaskID, req.Timestamp)
if err != nil {
err = &platform.Error{
Err: err,
Msg: "failed to force run",
if err == backend.ErrRunNotFound {
err = &platform.Error{
Code: platform.ENotFound,
Msg: "failed to force run",
Err: err,
}
}
EncodeError(ctx, err, w)
return
@ -791,7 +817,10 @@ func decodeForceRunRequest(ctx context.Context, r *http.Request) (forceRunReques
params := httprouter.ParamsFromContext(ctx)
tid := params.ByName("id")
if tid == "" {
return forceRunRequest{}, kerrors.InvalidDataf("you must provide a task ID")
return forceRunRequest{}, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a task ID",
}
}
var ti platform.ID
@ -839,10 +868,12 @@ func (h *TaskHandler) handleGetRun(w http.ResponseWriter, r *http.Request) {
run, err := h.TaskService.FindRunByID(ctx, req.TaskID, req.RunID)
if err != nil {
err = &platform.Error{
Err: err,
Code: platform.ENotFound,
Msg: "failed to find run",
if err == backend.ErrRunNotFound {
err = &platform.Error{
Err: err,
Msg: "failed to find run",
Code: platform.ENotFound,
}
}
EncodeError(ctx, err, w)
return
@ -863,11 +894,17 @@ func decodeGetRunRequest(ctx context.Context, r *http.Request) (*getRunRequest,
params := httprouter.ParamsFromContext(ctx)
tid := params.ByName("id")
if tid == "" {
return nil, kerrors.InvalidDataf("you must provide a task ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a task ID",
}
}
rid := params.ByName("rid")
if rid == "" {
return nil, kerrors.InvalidDataf("you must provide a run ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a run ID",
}
}
var ti, ri platform.ID
@ -893,11 +930,17 @@ func decodeCancelRunRequest(ctx context.Context, r *http.Request) (*cancelRunReq
params := httprouter.ParamsFromContext(ctx)
rid := params.ByName("rid")
if rid == "" {
return nil, kerrors.InvalidDataf("you must provide a run ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a run ID",
}
}
tid := params.ByName("id")
if tid == "" {
return nil, kerrors.InvalidDataf("you must provide a task ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a task ID",
}
}
var i platform.ID
@ -956,9 +999,12 @@ func (h *TaskHandler) handleRetryRun(w http.ResponseWriter, r *http.Request) {
run, err := h.TaskService.RetryRun(ctx, req.TaskID, req.RunID)
if err != nil {
err = &platform.Error{
Err: err,
Msg: "failed to retry run",
if err == backend.ErrRunNotFound {
err = &platform.Error{
Code: platform.ENotFound,
Msg: "failed to retry run",
Err: err,
}
}
EncodeError(ctx, err, w)
return
@ -977,11 +1023,17 @@ func decodeRetryRunRequest(ctx context.Context, r *http.Request) (*retryRunReque
params := httprouter.ParamsFromContext(ctx)
tid := params.ByName("id")
if tid == "" {
return nil, kerrors.InvalidDataf("you must provide a task ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a task ID",
}
}
rid := params.ByName("rid")
if rid == "" {
return nil, kerrors.InvalidDataf("you must provide a run ID")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "you must provide a run ID",
}
}
var ti, ri platform.ID
@ -1025,10 +1077,11 @@ func (t TaskService) FindTaskByID(ctx context.Context, id platform.ID) (*platfor
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err.Error() == backend.ErrTaskNotFound.Error() {
if err := CheckError(resp); err != nil {
if platform.ErrorCode(err) == platform.ENotFound {
// ErrTaskNotFound is expected as part of the FindTaskByID contract,
// so return that actual error instead of a different error that looks like it.
// TODO cleanup backend task service error implementation
return nil, backend.ErrTaskNotFound
}
return nil, err
@ -1079,7 +1132,7 @@ func (t TaskService) FindTasks(ctx context.Context, filter platform.TaskFilter)
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, 0, err
}
@ -1123,7 +1176,7 @@ func (t TaskService) CreateTask(ctx context.Context, tsk *platform.Task) error {
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -1164,7 +1217,7 @@ func (t TaskService) UpdateTask(ctx context.Context, id platform.ID, upd platfor
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -1239,7 +1292,7 @@ func (t TaskService) FindLogs(ctx context.Context, filter platform.LogFilter) ([
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, 0, err
}
@ -1289,7 +1342,7 @@ func (t TaskService) FindRuns(ctx context.Context, filter platform.RunFilter) ([
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, 0, err
}
@ -1328,10 +1381,11 @@ func (t TaskService) FindRunByID(ctx context.Context, taskID, runID platform.ID)
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err.Error() == backend.ErrRunNotFound.Error() {
if err := CheckError(resp); err != nil {
if platform.ErrorCode(err) == platform.ENotFound {
// ErrRunNotFound is expected as part of the FindRunByID contract,
// so return that actual error instead of a different error that looks like it.
// TODO cleanup backend error implementation
return nil, backend.ErrRunNotFound
}
@ -1367,13 +1421,13 @@ func (t TaskService) RetryRun(ctx context.Context, taskID, runID platform.ID) (*
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err.Error() == backend.ErrRunNotFound.Error() {
if err := CheckError(resp); err != nil {
if platform.ErrorCode(err) == platform.ENotFound {
// ErrRunNotFound is expected as part of the RetryRun contract,
// so return that actual error instead of a different error that looks like it.
// TODO cleanup backend task error implementation
return nil, backend.ErrRunNotFound
}
// RequestStillQueuedError is also part of the contract.
if e := backend.ParseRequestStillQueuedError(err.Error()); e != nil {
return nil, *e
@ -1411,8 +1465,8 @@ func (t TaskService) ForceRun(ctx context.Context, taskID platform.ID, scheduled
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err.Error() == backend.ErrRunNotFound.Error() {
if err := CheckError(resp); err != nil {
if platform.ErrorCode(err) == platform.ENotFound {
// ErrRunNotFound is expected as part of the RetryRun contract,
// so return that actual error instead of a different error that looks like it.
return nil, backend.ErrRunNotFound
@ -1458,7 +1512,7 @@ func (t TaskService) CancelRun(ctx context.Context, taskID, runID platform.ID) e
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}

View File

@ -10,7 +10,6 @@ import (
"github.com/golang/gddo/httputil"
platform "github.com/influxdata/influxdb"
pctx "github.com/influxdata/influxdb/context"
"github.com/influxdata/influxdb/kit/errors"
"github.com/julienschmidt/httprouter"
"go.uber.org/zap"
)
@ -125,7 +124,10 @@ func decodeGetTelegrafRequest(ctx context.Context, r *http.Request) (i platform.
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return i, errors.InvalidDataf("url missing id")
return i, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
if err := i.DecodeFromString(id); err != nil {
@ -254,7 +256,10 @@ func decodePutTelegrafRequest(ctx context.Context, r *http.Request) (*platform.T
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, errors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
i := new(platform.ID)
if err := i.DecodeFromString(id); err != nil {

View File

@ -9,7 +9,6 @@ import (
"path"
platform "github.com/influxdata/influxdb"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/julienschmidt/httprouter"
)
@ -97,7 +96,10 @@ func decodePostMemberRequest(ctx context.Context, r *http.Request) (*postMemberR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var rid platform.ID
@ -111,7 +113,10 @@ func decodePostMemberRequest(ctx context.Context, r *http.Request) (*postMemberR
}
if !u.ID.Valid() {
return nil, kerrors.InvalidDataf("user id missing or invalid")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "user id missing or invalid",
}
}
return &postMemberRequest{
@ -171,7 +176,10 @@ func decodeGetMembersRequest(ctx context.Context, r *http.Request) (*getMembersR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -215,7 +223,10 @@ func decodeDeleteMemberRequest(ctx context.Context, r *http.Request) (*deleteMem
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing resource id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing resource id",
}
}
var rid platform.ID
@ -225,7 +236,10 @@ func decodeDeleteMemberRequest(ctx context.Context, r *http.Request) (*deleteMem
id = params.ByName("userID")
if id == "" {
return nil, kerrors.InvalidDataf("url missing member id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing member id",
}
}
var mid platform.ID

View File

@ -11,7 +11,6 @@ import (
platform "github.com/influxdata/influxdb"
platcontext "github.com/influxdata/influxdb/context"
kerrors "github.com/influxdata/influxdb/kit/errors"
"github.com/julienschmidt/httprouter"
)
@ -217,7 +216,10 @@ func decodeGetUserRequest(ctx context.Context, r *http.Request) (*getUserRequest
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -258,7 +260,10 @@ func decodeDeleteUserRequest(ctx context.Context, r *http.Request) (*deleteUserR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -389,7 +394,10 @@ func decodePatchUserRequest(ctx context.Context, r *http.Request) (*patchUserReq
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID
@ -437,7 +445,7 @@ func (s *UserService) FindMe(ctx context.Context, id platform.ID) (*platform.Use
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -468,7 +476,7 @@ func (s *UserService) FindUserByID(ctx context.Context, id platform.ID) (*platfo
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -532,7 +540,7 @@ func (s *UserService) FindUsers(ctx context.Context, filter platform.UserFilter,
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, 0, err
}
@ -574,7 +582,7 @@ func (s *UserService) CreateUser(ctx context.Context, u *platform.User) error {
defer resp.Body.Close()
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return err
}
@ -614,7 +622,7 @@ func (s *UserService) UpdateUser(ctx context.Context, id platform.ID, upd platfo
}
defer resp.Body.Close()
if err := CheckError(resp, true); err != nil {
if err := CheckError(resp); err != nil {
return nil, err
}
@ -646,7 +654,7 @@ func (s *UserService) DeleteUser(ctx context.Context, id platform.ID) error {
}
defer resp.Body.Close()
return CheckErrorStatus(http.StatusNoContent, resp, true)
return CheckErrorStatus(http.StatusNoContent, resp)
}
func userIDPath(id platform.ID) string {
@ -684,7 +692,10 @@ func decodeGetUserLogRequest(ctx context.Context, r *http.Request) (*getUserLogR
params := httprouter.ParamsFromContext(ctx)
id := params.ByName("id")
if id == "" {
return nil, kerrors.InvalidDataf("url missing id")
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: "url missing id",
}
}
var i platform.ID

View File

@ -190,7 +190,10 @@ type postViewRequest struct {
func decodePostViewRequest(ctx context.Context, r *http.Request) (*postViewRequest, error) {
c := &platform.View{}
if err := json.NewDecoder(r.Body).Decode(c); err != nil {
return nil, err
return nil, &platform.Error{
Code: platform.EInvalid,
Msg: err.Error(),
}
}
return &postViewRequest{
View: c,
@ -317,7 +320,7 @@ func decodePatchViewRequest(ctx context.Context, r *http.Request) (*patchViewReq
if err := json.NewDecoder(r.Body).Decode(&upd); err != nil {
return nil, &platform.Error{
Code: platform.EInvalid,
Err: err,
Msg: err.Error(),
}
}
@ -334,7 +337,8 @@ func decodePatchViewRequest(ctx context.Context, r *http.Request) (*patchViewReq
var i platform.ID
if err := i.DecodeFromString(id); err != nil {
return nil, &platform.Error{
Err: err,
Code: platform.EInvalid,
Err: err,
}
}

View File

@ -303,7 +303,7 @@ func (s *WriteService) Write(ctx context.Context, orgID, bucketID platform.ID, r
}
defer resp.Body.Close()
return CheckError(resp, true)
return CheckError(resp)
}
func compressWithGzip(data io.Reader) (io.Reader, error) {