diff --git a/README.md b/README.md index 60187e94..a43ab906 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ It was made foremost for later separated from it and moved to this new repository because the library is useful per se. +The library requires at least Go 1.13. + ## Library design principles 1. SDK offers client functionality so it covers Grafana REST API with @@ -102,20 +104,7 @@ datasources. State of support for misc API parts noted below. | Frontend settings | - | | Admin | partially | -There is no exact roadmap. The integration tests are being run against the -following Grafana versions: - -* [6.7.1](./travis.yml) -* [6.6.2](/.travis.yml) -* [6.5.3](/.travis.yml) -* [6.4.5](/.travis.yml) - -With the following Go versions: - -* 1.14.x -* 1.13.x -* 1.12.x -* 1.11.x +The integration tests are being run for the Grafana and Go versions listed in [`.github/workflows/go.yml`](.github/workflows/go.yml). I still have interest to this library development but not always have time for it. So I gladly accept new contributions. Drop an issue or @@ -136,3 +125,17 @@ https://github.com/grafana-tools/sdk * [github.com/raintank/memo](https://github.com/raintank/memo) — send slack mentions to Grafana annotations. * [github.com/retzkek/grafctl](https://github.com/retzkek/grafctl) — backup/restore/track dashboards with git. * [github.com/grafana/grizzly](https://github.com/grafana/grizzly) — manage Grafana dashboards via CLI and libsonnet/jsonnet + +## Running tests + +* Unit tests: + ```command + $ go test ./... + ``` + +* Integration tests: + + ```command + $ GRAFANA_VERSION=6.7.1 docker-compose up -d + $ GRAFANA_INTEGRATION=1 go test ./... + ``` diff --git a/rest-admin.go b/rest-admin.go index 583066c4..5ff364a2 100644 --- a/rest-admin.go +++ b/rest-admin.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" ) // CreateUser creates a new global user. @@ -14,13 +15,17 @@ func (r *Client) CreateUser(ctx context.Context, user User) (StatusMessage, erro raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(user); err != nil { return StatusMessage{}, err } - if raw, _, err = r.post(ctx, "api/admin/users", nil, raw); err != nil { + if raw, code, err = r.post(ctx, "api/admin/users", nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -35,13 +40,17 @@ func (r *Client) UpdateUserPermissions(ctx context.Context, permissions UserPerm raw []byte reply StatusMessage err error + code int ) if raw, err = json.Marshal(permissions); err != nil { return StatusMessage{}, err } - if raw, _, err = r.put(ctx, fmt.Sprintf("api/admin/users/%d/permissions", uid), nil, raw); err != nil { + if raw, code, err = r.put(ctx, fmt.Sprintf("api/admin/users/%d/permissions", uid), nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } err = json.Unmarshal(raw, &reply) return reply, err } @@ -54,11 +63,15 @@ func (r *Client) SwitchUserContext(ctx context.Context, uid uint, oid uint) (Sta raw []byte resp StatusMessage err error + code int ) - if raw, _, err = r.post(ctx, fmt.Sprintf("/api/users/%d/using/%d", uid, oid), nil, raw); err != nil { + if raw, code, err = r.post(ctx, fmt.Sprintf("/api/users/%d/using/%d", uid, oid), nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } diff --git a/rest-alertnotification.go b/rest-alertnotification.go index 4cc336b5..ddce56ed 100644 --- a/rest-alertnotification.go +++ b/rest-alertnotification.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" ) // GetAllAlertNotifications gets all alert notification channels. @@ -34,7 +35,7 @@ func (c *Client) GetAllAlertNotifications(ctx context.Context) ([]AlertNotificat if raw, code, err = c.get(ctx, "api/alert-notifications", nil); err != nil { return nil, err } - if code != 200 { + if code != http.StatusOK { return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &an) @@ -53,7 +54,7 @@ func (c *Client) GetAlertNotificationUID(ctx context.Context, uid string) (Alert if raw, code, err = c.get(ctx, fmt.Sprintf("api/alert-notifications/uid/%s", uid), nil); err != nil { return an, err } - if code != 200 { + if code != http.StatusOK { return an, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &an) @@ -72,7 +73,7 @@ func (c *Client) GetAlertNotificationID(ctx context.Context, id uint) (AlertNoti if raw, code, err = c.get(ctx, fmt.Sprintf("api/alert-notifications/%d", id), nil); err != nil { return an, err } - if code != 200 { + if code != http.StatusOK { return an, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &an) @@ -93,7 +94,7 @@ func (c *Client) CreateAlertNotification(ctx context.Context, an AlertNotificati if raw, code, err = c.post(ctx, "api/alert-notifications", nil, raw); err != nil { return -1, err } - if code != 200 { + if code != http.StatusOK { return -1, fmt.Errorf("HTTP error %d: returns %s", code, raw) } result := struct { @@ -117,7 +118,7 @@ func (c *Client) UpdateAlertNotificationUID(ctx context.Context, an AlertNotific if raw, code, err = c.put(ctx, fmt.Sprintf("api/alert-notifications/uid/%s", uid), nil, raw); err != nil { return err } - if code != 200 { + if code != http.StatusOK { return fmt.Errorf("HTTP error %d: returns %s", code, raw) } return nil @@ -137,7 +138,7 @@ func (c *Client) UpdateAlertNotificationID(ctx context.Context, an AlertNotifica if raw, code, err = c.put(ctx, fmt.Sprintf("api/alert-notifications/%d", id), nil, raw); err != nil { return err } - if code != 200 { + if code != http.StatusOK { return fmt.Errorf("HTTP error %d: returns %s", code, raw) } return nil @@ -154,7 +155,7 @@ func (c *Client) DeleteAlertNotificationUID(ctx context.Context, uid string) err if raw, code, err = c.delete(ctx, fmt.Sprintf("api/alert-notifications/uid/%s", uid)); err != nil { return err } - if code != 200 { + if code != http.StatusOK { return fmt.Errorf("HTTP error %d: returns %s", code, raw) } return nil @@ -171,7 +172,7 @@ func (c *Client) DeleteAlertNotificationID(ctx context.Context, id uint) error { if raw, code, err = c.delete(ctx, fmt.Sprintf("api/alert-notifications/%d", id)); err != nil { return err } - if code != 200 { + if code != http.StatusOK { return fmt.Errorf("HTTP error %d: returns %s", code, raw) } return nil diff --git a/rest-annotation.go b/rest-annotation.go index a5c7c3d8..97975b42 100644 --- a/rest-annotation.go +++ b/rest-annotation.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "net/url" "strconv" "time" @@ -19,13 +20,17 @@ func (r *Client) CreateAnnotation(ctx context.Context, a CreateAnnotationRequest raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(a); err != nil { return StatusMessage{}, errors.Wrap(err, "marshal request") } - if raw, _, err = r.post(ctx, "api/annotations", nil, raw); err != nil { + if raw, code, err = r.post(ctx, "api/annotations", nil, raw); err != nil { return StatusMessage{}, errors.Wrap(err, "create annotation") } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, errors.Wrap(err, "unmarshal response message") } @@ -38,13 +43,17 @@ func (r *Client) PatchAnnotation(ctx context.Context, id uint, a PatchAnnotation raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(a); err != nil { return StatusMessage{}, errors.Wrap(err, "marshal request") } - if raw, _, err = r.patch(ctx, fmt.Sprintf("api/annotations/%d", id), nil, raw); err != nil { + if raw, code, err = r.patch(ctx, fmt.Sprintf("api/annotations/%d", id), nil, raw); err != nil { return StatusMessage{}, errors.Wrap(err, "patch annotation") } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, errors.Wrap(err, "unmarshal response message") } @@ -58,15 +67,19 @@ func (r *Client) GetAnnotations(ctx context.Context, params ...GetAnnotationsPar err error resp []AnnotationResponse requestParams = make(url.Values) + code int ) for _, p := range params { p(requestParams) } - if raw, _, err = r.get(ctx, "api/annotations", requestParams); err != nil { + if raw, code, err = r.get(ctx, "api/annotations", requestParams); err != nil { return nil, errors.Wrap(err, "get annotations") } + if code != http.StatusOK { + return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return nil, errors.Wrap(err, "unmarshal response message") } @@ -79,11 +92,15 @@ func (r *Client) DeleteAnnotation(ctx context.Context, id uint) (StatusMessage, raw []byte err error resp StatusMessage + code int ) - if raw, _, err = r.delete(ctx, fmt.Sprintf("api/annotations/%d", id)); err != nil { + if raw, code, err = r.delete(ctx, fmt.Sprintf("api/annotations/%d", id)); err != nil { return StatusMessage{}, errors.Wrap(err, "delete annotation") } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, errors.Wrap(err, "unmarshal response message") } diff --git a/rest-common.go b/rest-common.go new file mode 100644 index 00000000..7e13c061 --- /dev/null +++ b/rest-common.go @@ -0,0 +1,34 @@ +package sdk + +import ( + "errors" + "fmt" + "net/http" +) + +var ( + ErrNotFound = errors.New("not found") + ErrAlreadyExists = errors.New("already exists") + ErrNotAccessDenied = errors.New("access denied") + ErrNotAuthorized = errors.New("not authorized") + ErrCannotCreate = errors.New("cannot create; see body for details") +) + +func httpStatusCodeError(code int, message string, raw []byte) error { + switch code { + case http.StatusNotFound: + return fmt.Errorf("%s: %w", message, ErrNotFound) + + case http.StatusForbidden: + return fmt.Errorf("%s: %w", message, ErrNotAccessDenied) + + case http.StatusUnauthorized: + return fmt.Errorf("%s: %w", message, ErrNotAuthorized) + + case http.StatusPreconditionFailed: + return fmt.Errorf("%s: %w", message, ErrCannotCreate) + + default: + return fmt.Errorf("%s returned HTTP status code %d: %v", message, code, raw) + } +} diff --git a/rest-dashboard.go b/rest-dashboard.go index 653844c8..db049b76 100644 --- a/rest-dashboard.go +++ b/rest-dashboard.go @@ -24,6 +24,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "net/url" "strconv" "strings" @@ -161,21 +162,25 @@ func (r *Client) getRawDashboard(ctx context.Context, path string) ([]byte, Boar Meta BoardProperties `json:"meta"` Board json.RawMessage `json:"dashboard"` } - code int - err error + code int + err error + boardBytes []byte ) + if raw, code, err = r.get(ctx, fmt.Sprintf("api/dashboards/%s", path), nil); err != nil { return nil, BoardProperties{}, err } - if code != 200 { - return nil, BoardProperties{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + + if code != http.StatusOK { + return nil, BoardProperties{}, httpStatusCodeError(code, fmt.Sprintf("dashboard with path %q", path), raw) } + dec := json.NewDecoder(bytes.NewReader(raw)) dec.UseNumber() - if err := dec.Decode(&result); err != nil { - return nil, BoardProperties{}, errors.Wrap(err, "unmarshal board") - } - return []byte(result.Board), result.Meta, err + err = dec.Decode(&result) + boardBytes = []byte(result.Board) + + return boardBytes, result.Meta, err } // GetRawDashboardByUID loads a dashboard and its metadata from Grafana by dashboard uid. @@ -251,7 +256,7 @@ func (r *Client) Search(ctx context.Context, params ...SearchParam) ([]FoundBoar if raw, code, err = r.get(ctx, "api/search", q); err != nil { return nil, err } - if code != 200 { + if code != http.StatusOK { return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &boards) @@ -302,13 +307,14 @@ func (r *Client) SetDashboard(ctx context.Context, board Board, params SetDashbo if raw, code, err = r.post(ctx, "api/dashboards/db", nil, raw); err != nil { return StatusMessage{}, err } - if err = json.Unmarshal(raw, &resp); err != nil { - return StatusMessage{}, err - } - if code != 200 { - return resp, fmt.Errorf("HTTP error %d: returns %s", code, *resp.Message) + + if code != http.StatusOK { + return StatusMessage{}, httpStatusCodeError(code, fmt.Sprintf("database dashboard with uid %q", board.UID), raw) } - return resp, nil + + err = json.Unmarshal(raw, &resp) + + return resp, err } //SetRawDashboardWithParam sends the serialized along with request parameters @@ -330,7 +336,7 @@ func (r *Client) SetRawDashboardWithParam(ctx context.Context, request RawBoardR if err = json.Unmarshal(rawResp, &resp); err != nil { return StatusMessage{}, err } - if code != 200 { + if code != http.StatusOK { return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, *resp.Message) } return resp, nil @@ -365,13 +371,17 @@ func (r *Client) DeleteDashboard(ctx context.Context, slug string) (StatusMessag raw []byte reply StatusMessage err error + code int ) if slug, isBoardFromDB = cleanPrefix(slug); !isBoardFromDB { return StatusMessage{}, errors.New("only database dashboards (with 'db/' prefix in a slug) can be removed") } - if raw, _, err = r.delete(ctx, fmt.Sprintf("api/dashboards/db/%s", slug)); err != nil { + if raw, code, err = r.delete(ctx, fmt.Sprintf("api/dashboards/db/%s", slug)); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } err = json.Unmarshal(raw, &reply) return reply, err } @@ -383,11 +393,18 @@ func (r *Client) DeleteDashboardByUID(ctx context.Context, uid string) (StatusMe raw []byte reply StatusMessage err error + code int ) - if raw, _, err = r.delete(ctx, fmt.Sprintf("api/dashboards/uid/%s", uid)); err != nil { + if raw, code, err = r.delete(ctx, fmt.Sprintf("api/dashboards/uid/%s", uid)); err != nil { return StatusMessage{}, err } + + if code != http.StatusOK { + return StatusMessage{}, httpStatusCodeError(code, fmt.Sprintf("dashboard with uid %q", uid), raw) + } + err = json.Unmarshal(raw, &reply) + return reply, err } diff --git a/rest-dashboard_integration_test.go b/rest-dashboard_integration_test.go index dd2eef9d..91c11976 100644 --- a/rest-dashboard_integration_test.go +++ b/rest-dashboard_integration_test.go @@ -3,6 +3,7 @@ package sdk_test import ( "context" "encoding/json" + "errors" "io/ioutil" "testing" @@ -30,7 +31,9 @@ func Test_Dashboard_CRUD(t *testing.T) { board.ID = 1234 board.Title = "barfoo" - if _, err = client.DeleteDashboard(ctx, board.UpdateSlug()); err != nil { + _, err = client.DeleteDashboardByUID(ctx, board.UID) + + if !errors.Is(err, sdk.ErrNotFound) { t.Fatal(err) } @@ -85,7 +88,9 @@ func Test_Dashboard_CRUD_By_UID(t *testing.T) { board.Title = "foobar" //Cleanup if Already exists - if _, err = client.DeleteDashboardByUID(ctx, board.UID); err != nil { + _, err = client.DeleteDashboardByUID(ctx, board.UID) + + if !errors.Is(err, sdk.ErrNotFound) { t.Fatal(err) } diff --git a/rest-datasource.go b/rest-datasource.go index f5feee5d..38d589d2 100644 --- a/rest-datasource.go +++ b/rest-datasource.go @@ -23,6 +23,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" ) // GetAllDatasources gets all datasources. @@ -37,7 +38,7 @@ func (r *Client) GetAllDatasources(ctx context.Context) ([]Datasource, error) { if raw, code, err = r.get(ctx, "api/datasources", nil); err != nil { return nil, err } - if code != 200 { + if code != http.StatusOK { return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &ds) @@ -53,13 +54,17 @@ func (r *Client) GetDatasource(ctx context.Context, id uint) (Datasource, error) code int err error ) + if raw, code, err = r.get(ctx, fmt.Sprintf("api/datasources/%d", id), nil); err != nil { return ds, err } - if code != 200 { - return ds, fmt.Errorf("HTTP error %d: returns %s", code, raw) + + if code != http.StatusOK { + return ds, httpStatusCodeError(code, fmt.Sprintf("data source with id %d", id), raw) } + err = json.Unmarshal(raw, &ds) + return ds, err } @@ -75,7 +80,7 @@ func (r *Client) GetDatasourceByName(ctx context.Context, name string) (Datasour if raw, code, err = r.get(ctx, fmt.Sprintf("api/datasources/name/%s", name), nil); err != nil { return ds, err } - if code != 200 { + if code != http.StatusOK { return ds, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &ds) @@ -89,17 +94,22 @@ func (r *Client) CreateDatasource(ctx context.Context, ds Datasource) (StatusMes raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(ds); err != nil { return StatusMessage{}, err } - if raw, _, err = r.post(ctx, "api/datasources", nil, raw); err != nil { + if raw, code, err = r.post(ctx, "api/datasources", nil, raw); err != nil { return StatusMessage{}, err } - if err = json.Unmarshal(raw, &resp); err != nil { - return StatusMessage{}, err + + if code != http.StatusOK { + return StatusMessage{}, httpStatusCodeError(code, fmt.Sprintf("data source with name %q", ds.Name), raw) } - return resp, nil + + err = json.Unmarshal(raw, &resp) + + return resp, err } // UpdateDatasource updates a datasource from data passed in argument. @@ -109,17 +119,22 @@ func (r *Client) UpdateDatasource(ctx context.Context, ds Datasource) (StatusMes raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(ds); err != nil { - return StatusMessage{}, err + return resp, err } - if raw, _, err = r.put(ctx, fmt.Sprintf("api/datasources/%d", ds.ID), nil, raw); err != nil { - return StatusMessage{}, err + if raw, code, err = r.put(ctx, fmt.Sprintf("api/datasources/%d", ds.ID), nil, raw); err != nil { + return resp, err } - if err = json.Unmarshal(raw, &resp); err != nil { - return StatusMessage{}, err + + if code != http.StatusOK { + return StatusMessage{}, httpStatusCodeError(code, fmt.Sprintf("data source with name %q", ds.Name), raw) } - return resp, nil + + err = json.Unmarshal(raw, &resp) + + return resp, err } // DeleteDatasource deletes an existing datasource by ID. @@ -129,10 +144,14 @@ func (r *Client) DeleteDatasource(ctx context.Context, id uint) (StatusMessage, raw []byte reply StatusMessage err error + code int ) - if raw, _, err = r.delete(ctx, fmt.Sprintf("api/datasources/%d", id)); err != nil { + if raw, code, err = r.delete(ctx, fmt.Sprintf("api/datasources/%d", id)); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } err = json.Unmarshal(raw, &reply) return reply, err } @@ -144,10 +163,14 @@ func (r *Client) DeleteDatasourceByName(ctx context.Context, name string) (Statu raw []byte reply StatusMessage err error + code int ) - if raw, _, err = r.delete(ctx, fmt.Sprintf("api/datasources/name/%s", name)); err != nil { + if raw, code, err = r.delete(ctx, fmt.Sprintf("api/datasources/name/%s", name)); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } err = json.Unmarshal(raw, &reply) return reply, err } @@ -164,7 +187,7 @@ func (r *Client) GetDatasourceTypes(ctx context.Context) (map[string]DatasourceT if raw, code, err = r.get(ctx, "api/datasources/plugins", nil); err != nil { return nil, err } - if code != 200 { + if code != http.StatusOK { return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &dsTypes) diff --git a/rest-folder.go b/rest-folder.go index da4dc589..4a59b87f 100644 --- a/rest-folder.go +++ b/rest-folder.go @@ -23,6 +23,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "net/url" "strconv" ) @@ -45,7 +46,7 @@ func (r *Client) GetAllFolders(ctx context.Context, params ...GetFolderParams) ( if raw, code, err = r.get(ctx, "api/folders", requestParams); err != nil { return nil, err } - if code != 200 { + if code != http.StatusOK { return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &fs) @@ -64,7 +65,7 @@ func (r *Client) GetFolderByUID(ctx context.Context, UID string) (Folder, error) if raw, code, err = r.get(ctx, fmt.Sprintf("api/folders/%s", UID), nil); err != nil { return f, err } - if code != 200 { + if code != http.StatusOK { return f, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &f) @@ -87,7 +88,7 @@ func (r *Client) CreateFolder(ctx context.Context, f Folder) (Folder, error) { if raw, code, err = r.post(ctx, "api/folders", nil, raw); err != nil { return rf, err } - if code != 200 { + if code != http.StatusOK { return rf, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &rf) @@ -110,7 +111,7 @@ func (r *Client) UpdateFolderByUID(ctx context.Context, f Folder) (Folder, error if raw, code, err = r.put(ctx, fmt.Sprintf("api/folders/%s", f.UID), nil, raw); err != nil { return rf, err } - if code != 200 { + if code != http.StatusOK { return f, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &rf) @@ -128,7 +129,7 @@ func (r *Client) DeleteFolderByUID(ctx context.Context, UID string) (bool, error if raw, code, err = r.delete(ctx, fmt.Sprintf("api/folders/%s", UID)); err != nil { return false, err } - if code != 200 { + if code != http.StatusOK { return false, fmt.Errorf("HTTP error %d: returns %s", code, raw) } return true, err @@ -149,7 +150,7 @@ func (r *Client) GetFolderByID(ctx context.Context, ID int) (Folder, error) { if raw, code, err = r.get(ctx, fmt.Sprintf("api/folders/id/%d", ID), nil); err != nil { return f, err } - if code != 200 { + if code != http.StatusOK { return f, fmt.Errorf("HTTP error %d: returns %s", code, raw) } err = json.Unmarshal(raw, &f) diff --git a/rest-get_health.go b/rest-get_health.go index aa1b0e1d..5e407039 100644 --- a/rest-get_health.go +++ b/rest-get_health.go @@ -22,6 +22,8 @@ package sdk import ( "context" "encoding/json" + "fmt" + "net/http" ) // HealthResponse represents the health of grafana server @@ -35,14 +37,17 @@ type HealthResponse struct { // Reflects GET BaseURL API call. func (r *Client) GetHealth(ctx context.Context) (HealthResponse, error) { var ( - raw []byte - err error + raw []byte + err error + health HealthResponse + code int ) - if raw, _, err = r.get(ctx, "/api/health", nil); err != nil { + if raw, code, err = r.get(ctx, "/api/health", nil); err != nil { return HealthResponse{}, err } - - health := HealthResponse{} + if code != http.StatusOK { + return HealthResponse{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err := json.Unmarshal(raw, &health); err != nil { return HealthResponse{}, err } diff --git a/rest-org.go b/rest-org.go index 20116bd2..dd658666 100644 --- a/rest-org.go +++ b/rest-org.go @@ -34,13 +34,17 @@ func (r *Client) CreateOrg(ctx context.Context, org Org) (StatusMessage, error) raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(org); err != nil { return StatusMessage{}, err } - if raw, _, err = r.post(ctx, "api/orgs", nil, raw); err != nil { + if raw, code, err = r.post(ctx, "api/orgs", nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -59,7 +63,6 @@ func (r *Client) GetAllOrgs(ctx context.Context) ([]Org, error) { if raw, code, err = r.get(ctx, "api/orgs", nil); err != nil { return orgs, err } - if code != http.StatusOK { return orgs, fmt.Errorf("HTTP error %d: returns %s", code, raw) } @@ -106,7 +109,6 @@ func (r *Client) GetOrgById(ctx context.Context, oid uint) (Org, error) { if raw, code, err = r.get(ctx, fmt.Sprintf("api/orgs/%d", oid), nil); err != nil { return org, err } - if code != http.StatusOK { return org, fmt.Errorf("HTTP error %d: returns %s", code, raw) } @@ -130,7 +132,6 @@ func (r *Client) GetOrgByOrgName(ctx context.Context, name string) (Org, error) if raw, code, err = r.get(ctx, fmt.Sprintf("api/orgs/name/%s", name), nil); err != nil { return org, err } - if code != http.StatusOK { return org, fmt.Errorf("HTTP error %d: returns %s", code, raw) } @@ -149,13 +150,17 @@ func (r *Client) UpdateActualOrg(ctx context.Context, org Org) (StatusMessage, e raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(org); err != nil { return StatusMessage{}, err } - if raw, _, err = r.put(ctx, "api/org", nil, raw); err != nil { + if raw, code, err = r.put(ctx, "api/org", nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -169,13 +174,17 @@ func (r *Client) UpdateOrg(ctx context.Context, org Org, oid uint) (StatusMessag raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(org); err != nil { return StatusMessage{}, err } - if raw, _, err = r.put(ctx, fmt.Sprintf("api/orgs/%d", oid), nil, raw); err != nil { + if raw, code, err = r.put(ctx, fmt.Sprintf("api/orgs/%d", oid), nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -189,10 +198,14 @@ func (r *Client) DeleteOrg(ctx context.Context, oid uint) (StatusMessage, error) raw []byte resp StatusMessage err error + code int ) - if raw, _, err = r.delete(ctx, fmt.Sprintf("api/orgs/%d", oid)); err != nil { + if raw, code, err = r.delete(ctx, fmt.Sprintf("api/orgs/%d", oid)); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -252,13 +265,17 @@ func (r *Client) AddActualOrgUser(ctx context.Context, userRole UserRole) (Statu raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(userRole); err != nil { return StatusMessage{}, err } - if raw, _, err = r.post(ctx, "api/org/users", nil, raw); err != nil { + if raw, code, err = r.post(ctx, "api/org/users", nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -272,13 +289,17 @@ func (r *Client) UpdateActualOrgUser(ctx context.Context, user UserRole, uid uin raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(user); err != nil { return StatusMessage{}, err } - if raw, _, err = r.post(ctx, fmt.Sprintf("api/org/users/%d", uid), nil, raw); err != nil { + if raw, code, err = r.post(ctx, fmt.Sprintf("api/org/users/%d", uid), nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -292,10 +313,14 @@ func (r *Client) DeleteActualOrgUser(ctx context.Context, uid uint) (StatusMessa raw []byte reply StatusMessage err error + code int ) - if raw, _, err = r.delete(ctx, fmt.Sprintf("api/org/users/%d", uid)); err != nil { + if raw, code, err = r.delete(ctx, fmt.Sprintf("api/org/users/%d", uid)); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } err = json.Unmarshal(raw, &reply) return reply, err } @@ -307,13 +332,17 @@ func (r *Client) AddOrgUser(ctx context.Context, user UserRole, oid uint) (Statu raw []byte reply StatusMessage err error + code int ) if raw, err = json.Marshal(user); err != nil { return StatusMessage{}, err } - if raw, _, err = r.post(ctx, fmt.Sprintf("api/orgs/%d/users", oid), nil, raw); err != nil { + if raw, code, err = r.post(ctx, fmt.Sprintf("api/orgs/%d/users", oid), nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } err = json.Unmarshal(raw, &reply) return reply, err } @@ -325,13 +354,17 @@ func (r *Client) UpdateOrgUser(ctx context.Context, user UserRole, oid, uid uint raw []byte reply StatusMessage err error + code int ) if raw, err = json.Marshal(user); err != nil { return StatusMessage{}, err } - if raw, _, err = r.patch(ctx, fmt.Sprintf("api/orgs/%d/users/%d", oid, uid), nil, raw); err != nil { + if raw, code, err = r.patch(ctx, fmt.Sprintf("api/orgs/%d/users/%d", oid, uid), nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } err = json.Unmarshal(raw, &reply) return reply, err } @@ -343,10 +376,14 @@ func (r *Client) DeleteOrgUser(ctx context.Context, oid, uid uint) (StatusMessag raw []byte reply StatusMessage err error + code int ) - if raw, _, err = r.delete(ctx, fmt.Sprintf("api/orgs/%d/users/%d", oid, uid)); err != nil { + if raw, code, err = r.delete(ctx, fmt.Sprintf("api/orgs/%d/users/%d", oid, uid)); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } err = json.Unmarshal(raw, &reply) return reply, err } @@ -358,13 +395,17 @@ func (r *Client) UpdateActualOrgPreferences(ctx context.Context, prefs Preferenc raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(prefs); err != nil { return StatusMessage{}, err } - if raw, _, err = r.put(ctx, "api/org/preferences/", nil, raw); err != nil { + if raw, code, err = r.put(ctx, "api/org/preferences/", nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -377,13 +418,12 @@ func (r *Client) GetActualOrgPreferences(ctx context.Context) (Preferences, erro var ( raw []byte pref Preferences - code int err error + code int ) if raw, code, err = r.get(ctx, "/api/org/preferences", nil); err != nil { return pref, err } - if code != http.StatusOK { return pref, fmt.Errorf("HTTP error %d: returns %s", code, raw) } @@ -402,13 +442,17 @@ func (r *Client) UpdateActualOrgAddress(ctx context.Context, address Address) (S raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(address); err != nil { return StatusMessage{}, err } - if raw, _, err = r.put(ctx, "api/org/address", nil, raw); err != nil { + if raw, code, err = r.put(ctx, "api/org/address", nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } @@ -422,13 +466,17 @@ func (r *Client) UpdateOrgAddress(ctx context.Context, address Address, oid uint raw []byte resp StatusMessage err error + code int ) if raw, err = json.Marshal(address); err != nil { return StatusMessage{}, err } - if raw, _, err = r.put(ctx, fmt.Sprintf("api/orgs/%d/address", oid), nil, raw); err != nil { + if raw, code, err = r.put(ctx, fmt.Sprintf("api/orgs/%d/address", oid), nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err } diff --git a/rest-user.go b/rest-user.go index 1b4dd4ce..fb07ad0f 100644 --- a/rest-user.go +++ b/rest-user.go @@ -24,6 +24,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "net/url" ) @@ -39,7 +40,7 @@ func (r *Client) GetActualUser(ctx context.Context) (User, error) { if raw, code, err = r.get(ctx, "api/user", nil); err != nil { return user, err } - if code != 200 { + if code != http.StatusOK { return user, fmt.Errorf("HTTP error %d: returns %s", code, raw) } dec := json.NewDecoder(bytes.NewReader(raw)) @@ -62,7 +63,7 @@ func (r *Client) GetUser(ctx context.Context, id uint) (User, error) { if raw, code, err = r.get(ctx, fmt.Sprintf("api/users/%d", id), nil); err != nil { return user, err } - if code != 200 { + if code != http.StatusOK { return user, fmt.Errorf("HTTP error %d: returns %s", code, raw) } dec := json.NewDecoder(bytes.NewReader(raw)) @@ -88,7 +89,7 @@ func (r *Client) GetAllUsers(ctx context.Context) ([]User, error) { if raw, code, err = r.get(ctx, "api/users", params); err != nil { return users, err } - if code != 200 { + if code != http.StatusOK { return users, fmt.Errorf("HTTP error %d: returns %s", code, raw) } dec := json.NewDecoder(bytes.NewReader(raw)) @@ -134,7 +135,7 @@ func (r *Client) SearchUsersWithPaging(ctx context.Context, query *string, perpa if raw, code, err = r.get(ctx, "api/users/search", params); err != nil { return pageUsers, err } - if code != 200 { + if code != http.StatusOK { return pageUsers, fmt.Errorf("HTTP error %d: returns %s", code, raw) } dec := json.NewDecoder(bytes.NewReader(raw)) @@ -152,11 +153,14 @@ func (r *Client) SwitchActualUserContext(ctx context.Context, oid uint) (StatusM raw []byte resp StatusMessage err error + code int ) - - if raw, _, err = r.post(ctx, fmt.Sprintf("/api/user/using/%d", oid), nil, raw); err != nil { + if raw, code, err = r.post(ctx, fmt.Sprintf("/api/user/using/%d", oid), nil, raw); err != nil { return StatusMessage{}, err } + if code != http.StatusOK { + return StatusMessage{}, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } if err = json.Unmarshal(raw, &resp); err != nil { return StatusMessage{}, err }