feat(httpc): extend httpc Client with JSON shorthand methods

making most common API calls super easy to get up and running
pull/15967/head
Johnny Steenbergen 2019-12-11 19:26:02 -08:00 committed by Johnny Steenbergen
parent bd67d3d368
commit bf86cce1f1
10 changed files with 98 additions and 21 deletions

View File

@ -852,7 +852,7 @@ func (s *BucketService) CreateBucket(ctx context.Context, b *influxdb.Bucket) er
var br bucketResponse
err := s.Client.
Post(httpc.BodyJSON(newBucket(b)), prefixBuckets).
PostJSON(newBucket(b), prefixBuckets).
DecodeJSON(&br).
Do(ctx)
if err != nil {
@ -872,7 +872,7 @@ func (s *BucketService) CreateBucket(ctx context.Context, b *influxdb.Bucket) er
func (s *BucketService) UpdateBucket(ctx context.Context, id influxdb.ID, upd influxdb.BucketUpdate) (*influxdb.Bucket, error) {
var br bucketResponse
err := s.Client.
Patch(httpc.BodyJSON(newBucketUpdate(&upd)), bucketIDPath(id)).
PatchJSON(newBucketUpdate(&upd), bucketIDPath(id)).
DecodeJSON(&br).
Do(ctx)
if err != nil {

View File

@ -1129,7 +1129,7 @@ func (s *DashboardService) FindDashboards(ctx context.Context, filter platform.D
// CreateDashboard creates a new dashboard and sets b.ID with the new identifier.
func (s *DashboardService) CreateDashboard(ctx context.Context, d *platform.Dashboard) error {
return s.Client.
Post(httpc.BodyJSON(d), prefixDashboards).
PostJSON(d, prefixDashboards).
DecodeJSON(d).
Do(ctx)
}
@ -1139,7 +1139,7 @@ func (s *DashboardService) CreateDashboard(ctx context.Context, d *platform.Dash
func (s *DashboardService) UpdateDashboard(ctx context.Context, id platform.ID, upd platform.DashboardUpdate) (*platform.Dashboard, error) {
var d platform.Dashboard
err := s.Client.
Patch(httpc.BodyJSON(upd), prefixDashboards, id.String()).
PatchJSON(upd, prefixDashboards, id.String()).
DecodeJSON(&d).
Do(ctx)
if err != nil {
@ -1164,7 +1164,7 @@ func (s *DashboardService) DeleteDashboard(ctx context.Context, id platform.ID)
// AddDashboardCell adds a cell to a dashboard.
func (s *DashboardService) AddDashboardCell(ctx context.Context, id platform.ID, c *platform.Cell, opts platform.AddDashboardCellOptions) error {
return s.Client.
Post(httpc.BodyJSON(c), cellPath(id)).
PostJSON(c, cellPath(id)).
DecodeJSON(c).
Do(ctx)
}
@ -1186,7 +1186,7 @@ func (s *DashboardService) UpdateDashboardCell(ctx context.Context, dashboardID,
var c platform.Cell
err := s.Client.
Patch(httpc.BodyJSON(upd), dashboardCellIDPath(dashboardID, cellID)).
PatchJSON(upd, dashboardCellIDPath(dashboardID, cellID)).
DecodeJSON(&c).
Do(ctx)
if err != nil {
@ -1214,7 +1214,7 @@ func (s *DashboardService) GetDashboardCellView(ctx context.Context, dashboardID
func (s *DashboardService) UpdateDashboardCellView(ctx context.Context, dashboardID, cellID platform.ID, upd platform.ViewUpdate) (*platform.View, error) {
var dcv dashboardCellViewResponse
err := s.Client.
Patch(httpc.BodyJSON(upd), cellViewPath(dashboardID, cellID)).
PatchJSON(upd, cellViewPath(dashboardID, cellID)).
DecodeJSON(&dcv).
Do(ctx)
if err != nil {
@ -1226,7 +1226,7 @@ func (s *DashboardService) UpdateDashboardCellView(ctx context.Context, dashboar
// ReplaceDashboardCells replaces all cells in a dashboard
func (s *DashboardService) ReplaceDashboardCells(ctx context.Context, id platform.ID, cs []*platform.Cell) error {
return s.Client.
Put(httpc.BodyJSON(cs), cellPath(id)).
PutJSON(cs, cellPath(id)).
// TODO: previous implementation did not do anything with the response except validate it is valid json.
// seems likely we should have to overwrite (:sadpanda:) the incoming cs...
DecodeJSON(&dashboardCellsResponse{}).

View File

@ -582,7 +582,7 @@ func (s *LabelService) FindResourceLabels(ctx context.Context, filter influxdb.L
func (s *LabelService) CreateLabel(ctx context.Context, l *influxdb.Label) error {
var lr labelResponse
err := s.Client.
Post(httpc.BodyJSON(l), prefixLabels).
PostJSON(l, prefixLabels).
DecodeJSON(&lr).
Do(ctx)
if err != nil {
@ -598,7 +598,7 @@ func (s *LabelService) CreateLabel(ctx context.Context, l *influxdb.Label) error
func (s *LabelService) UpdateLabel(ctx context.Context, id influxdb.ID, upd influxdb.LabelUpdate) (*influxdb.Label, error) {
var lr labelResponse
err := s.Client.
Patch(httpc.BodyJSON(upd), labelIDPath(id)).
PatchJSON(upd, labelIDPath(id)).
DecodeJSON(&lr).
Do(ctx)
if err != nil {
@ -622,7 +622,7 @@ func (s *LabelService) CreateLabelMapping(ctx context.Context, m *influxdb.Label
urlPath := resourceIDPath(m.ResourceType, m.ResourceID, "labels")
return s.Client.
Post(httpc.BodyJSON(m), urlPath).
PostJSON(m, urlPath).
DecodeJSON(m).
Do(ctx)
}

View File

@ -661,7 +661,7 @@ func (s *NotificationEndpointService) CreateNotificationEndpoint(ctx context.Con
// the token/auth. its a nothing burger here
var resp notificationEndpointDecoder
err := s.Client.
Post(httpc.BodyJSON(&notificationEndpointEncoder{ne: ne}), prefixNotificationEndpoints).
PostJSON(&notificationEndpointEncoder{ne: ne}, prefixNotificationEndpoints).
DecodeJSON(&resp).
Do(ctx)
if err != nil {
@ -679,7 +679,7 @@ func (s *NotificationEndpointService) UpdateNotificationEndpoint(ctx context.Con
// userID is ignored since userID is grabbed off the http auth set on the client
var resp notificationEndpointDecoder
err := s.Client.
Put(httpc.BodyJSON(&notificationEndpointEncoder{ne: ne}), prefixNotificationEndpoints, id.String()).
PutJSON(&notificationEndpointEncoder{ne: ne}, prefixNotificationEndpoints, id.String()).
DecodeJSON(&resp).
Do(ctx)
if err != nil {
@ -697,7 +697,7 @@ func (s *NotificationEndpointService) PatchNotificationEndpoint(ctx context.Cont
var resp notificationEndpointDecoder
err := s.Client.
Patch(httpc.BodyJSON(upd), prefixNotificationEndpoints, id.String()).
PatchJSON(upd, prefixNotificationEndpoints, id.String()).
DecodeJSON(&resp).
Do(ctx)
if err != nil {

View File

@ -693,7 +693,7 @@ func (s *OrganizationService) CreateOrganization(ctx context.Context, o *influxd
}
return s.Client.
Post(httpc.BodyJSON(o), organizationPath).
PostJSON(o, organizationPath).
DecodeJSON(o).
Do(ctx)
}
@ -708,7 +708,7 @@ func (s *OrganizationService) UpdateOrganization(ctx context.Context, id influxd
var o influxdb.Organization
err := s.Client.
Patch(httpc.BodyJSON(upd), organizationPath, id.String()).
PatchJSON(upd, organizationPath, id.String()).
DecodeJSON(&o).
Do(ctx)
if err != nil {

View File

@ -494,7 +494,7 @@ func (s *TelegrafService) FindTelegrafConfigs(ctx context.Context, f platform.Te
func (s *TelegrafService) CreateTelegrafConfig(ctx context.Context, tc *platform.TelegrafConfig, userID platform.ID) error {
var teleResp platform.TelegrafConfig
err := s.client.
Post(httpc.BodyJSON(tc), prefixTelegraf).
PostJSON(tc, prefixTelegraf).
DecodeJSON(&teleResp).
Do(ctx)
if err != nil {

View File

@ -298,7 +298,7 @@ func (s *UserResourceMappingService) CreateUserResourceMapping(ctx context.Conte
urlPath := resourceIDPath(m.ResourceType, m.ResourceID, string(m.UserType)+"s")
return s.Client.
Post(httpc.BodyJSON(influxdb.User{ID: m.UserID}), urlPath).
PostJSON(influxdb.User{ID: m.UserID}, urlPath).
DecodeJSON(m).
Do(ctx)
}

View File

@ -491,7 +491,7 @@ func (s *VariableService) CreateVariable(ctx context.Context, m *platform.Variab
}
return s.Client.
Post(httpc.BodyJSON(m), prefixVariables).
PostJSON(m, prefixVariables).
DecodeJSON(m).
Do(ctx)
}
@ -500,7 +500,7 @@ func (s *VariableService) CreateVariable(ctx context.Context, m *platform.Variab
func (s *VariableService) UpdateVariable(ctx context.Context, id platform.ID, update *platform.VariableUpdate) (*platform.Variable, error) {
var m platform.Variable
err := s.Client.
Patch(httpc.BodyJSON(update), prefixVariables, id.String()).
PatchJSON(update, prefixVariables, id.String()).
DecodeJSON(&m).
Do(ctx)
if err != nil {
@ -513,7 +513,7 @@ func (s *VariableService) UpdateVariable(ctx context.Context, id platform.ID, up
// ReplaceVariable replaces a single variable
func (s *VariableService) ReplaceVariable(ctx context.Context, variable *platform.Variable) error {
return s.Client.
Put(httpc.BodyJSON(variable), prefixVariables, variable.ID.String()).
PutJSON(variable, prefixVariables, variable.ID.String()).
DecodeJSON(variable).
Do(ctx)
}

View File

@ -90,16 +90,35 @@ func (c *Client) Patch(bFn BodyFn, urlPath string, rest ...string) *Req {
return c.Req(http.MethodPatch, bFn, urlPath, rest...)
}
// PatchJSON generates a PATCH request. This is to be used with value or pointer to value type.
// Providing a stream/reader will result in disappointment.
func (c *Client) PatchJSON(v interface{}, urlPath string, rest ...string) *Req {
return c.Patch(BodyJSON(v), urlPath, rest...)
}
// Post generates a POST request.
func (c *Client) Post(bFn BodyFn, urlPath string, rest ...string) *Req {
return c.Req(http.MethodPost, bFn, urlPath, rest...)
}
// PostJSON generates a POST request and json encodes the body. This is to be
// used with value or pointer to value type. Providing a stream/reader will result
// in disappointment.
func (c *Client) PostJSON(v interface{}, urlPath string, rest ...string) *Req {
return c.Post(BodyJSON(v), urlPath, rest...)
}
// Put generates a PUT request.
func (c *Client) Put(bFn BodyFn, urlPath string, rest ...string) *Req {
return c.Req(http.MethodPut, bFn, urlPath, rest...)
}
// PutJSON generates a PUT request. This is to be used with value or pointer to value type.
// Providing a stream/reader will result in disappointment.
func (c *Client) PutJSON(v interface{}, urlPath string, rest ...string) *Req {
return c.Put(BodyJSON(v), urlPath, rest...)
}
// Req constructs a request.
func (c *Client) Req(method string, bFn BodyFn, urlPath string, rest ...string) *Req {
bodyF := BodyEmpty

View File

@ -116,8 +116,11 @@ func TestClient(t *testing.T) {
for _, encTest := range encodingTests {
t.Run(encTest.name, func(t *testing.T) {
t.Helper()
for _, authTest := range authTests {
fn := func(t *testing.T) {
t.Helper()
client, fakeDoer := authTest.clientFn(tt.status, encTest.respFn, tt.clientOpts...)
req := tt.reqFn(client, "/new/path/heres", tt.reqBody).
@ -283,6 +286,61 @@ func TestClient(t *testing.T) {
})
}
})
t.Run("PatchJSON PostJSON PutJSON with request bodies", func(t *testing.T) {
methods := []struct {
name string
methodCallFn func(client *Client, urlPath string, v interface{}) *Req
}{
{
name: "PATCH",
methodCallFn: func(client *Client, urlPath string, v interface{}) *Req {
return client.PatchJSON(v, urlPath)
},
},
{
name: "POST",
methodCallFn: func(client *Client, urlPath string, v interface{}) *Req {
return client.PostJSON(v, urlPath)
},
},
{
name: "PUT",
methodCallFn: func(client *Client, urlPath string, v interface{}) *Req {
return client.PutJSON(v, urlPath)
},
},
}
for _, method := range methods {
t.Run(method.name, func(t *testing.T) {
tests := []struct {
name string
testCase
}{
{
name: "handles json req body",
testCase: testCase{
status: 200,
reqFn: func(client *Client, urlPath string, body reqBody) *Req {
return method.methodCallFn(client, urlPath, body)
},
reqBody: reqBody{
Foo: "foo 1",
Bar: 31,
},
},
},
}
for _, tt := range tests {
tt.method = method.name
t.Run(tt.name, testWithRespBody(tt.testCase))
}
})
}
})
}
type fakeDoer struct {