Skip to content

Commit

Permalink
fix: update to make CRUD works in good cases
Browse files Browse the repository at this point in the history
  • Loading branch information
lriberon committed Jan 6, 2025
1 parent 49628ea commit a407b4f
Show file tree
Hide file tree
Showing 11 changed files with 257 additions and 214 deletions.
8 changes: 4 additions & 4 deletions common/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package common
import "context"

// API interface
type API[T any] interface {
Create(ctx context.Context, params T) (*int, error)
Read(ctx context.Context, id int) (*T, error)
type API[T any, I comparable] interface {
Create(ctx context.Context, params T) (*I, error)
Read(ctx context.Context, id I) (*T, error)
Update(ctx context.Context, params T) (*T, error)
Delete(ctx context.Context, id int) error
Delete(ctx context.Context, id I) error
}
2 changes: 1 addition & 1 deletion datadome-client-go/client_custom_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func (c *ClientCustomRule) Read(ctx context.Context, id int) (*CustomRule, error

customRule := &CustomRule{}
for _, v := range customRules.CustomRules {
if v.ID == id {
if *v.ID == id {
customRule = &v
}
}
Expand Down
84 changes: 29 additions & 55 deletions datadome-client-go/client_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,13 @@ func NewClientEndpoint(host, password *string) (*ClientEndpoint, error) {
}

// doRequest on the DataDome API with given http.Request and HttpResponse
func (c *ClientEndpoint) doRequest(req *http.Request, httpResponse *HttpResponse) (*HttpResponse, error) {
func (c *ClientEndpoint) doRequest(req *http.Request, endpoint *Endpoint) error {
// Add apikey as a header on each request for authentication
// Add also withoutTraffic parameter to true to have better performances
q := req.URL.Query()
req.Header.Set("x-api-key", c.Token)
q.Add("withoutTraffic", "true")
req.URL.RawQuery = q.Encode()

res, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
return err
}
defer func() {
err = res.Body.Close()
Expand All @@ -61,54 +57,45 @@ func (c *ClientEndpoint) doRequest(req *http.Request, httpResponse *HttpResponse

body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
return err
}

if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status: %d, body: %s", res.StatusCode, body)
if res.StatusCode < 200 || res.StatusCode > 299 {
return fmt.Errorf("status: %d, body: %s", res.StatusCode, body)
}

log.Printf("[DEBUG] %s\n", body)

err = json.Unmarshal(body, httpResponse)
if err != nil {
return nil, err
}

if httpResponse.Status < 200 || httpResponse.Status > 299 {
return nil, fmt.Errorf("status: %d, body: %s", res.StatusCode, httpResponse.Errors)
if endpoint != nil {
err = json.Unmarshal(body, endpoint)
if err != nil {
return err
}
}

return httpResponse, err
return err
}

// Read endpoint information by its ID from the API management
func (c *ClientEndpoint) Read(ctx context.Context, id int) (*Endpoint, error) {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%d", c.HostURL, id), nil)
func (c *ClientEndpoint) Read(ctx context.Context, id string) (*Endpoint, error) {
req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/%s", c.HostURL, id), nil)
if err != nil {
return nil, err
}

endpoint := &Endpoint{}
resp := &HttpResponse{Data: endpoint}

_, err = c.doRequest(req, resp)
err = c.doRequest(req, endpoint)
if err != nil {
return nil, err
}
if resp.Status != 200 {
return nil, fmt.Errorf("response status is %d", resp.Status)
}

return endpoint, nil
}

// Create new endpoint with given Endpoint parameters
func (c *ClientEndpoint) Create(ctx context.Context, params Endpoint) (*int, error) {
reqBody := HttpRequest{
Data: params,
}
rb, err := json.Marshal(reqBody)
func (c *ClientEndpoint) Create(ctx context.Context, params Endpoint) (*string, error) {
rb, err := json.Marshal(params)
if err != nil {
return nil, err
}
Expand All @@ -122,27 +109,21 @@ func (c *ClientEndpoint) Create(ctx context.Context, params Endpoint) (*int, err
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")

id := &ID{}
resp := &HttpResponse{Data: id}
endpoint := &Endpoint{}

resp, err = c.doRequest(req, resp)
err = c.doRequest(req, endpoint)
if err != nil {
return nil, err
}
if resp.Status != 201 {
return nil, fmt.Errorf("response status is %d", resp.Status)
}

return &id.ID, nil
return endpoint.ID, nil
}

// Update endpoint by its ID
func (c *ClientEndpoint) Update(ctx context.Context, params Endpoint) (*Endpoint, error) {
reqBody := HttpRequest{
Data: params,
}
rb, err := json.Marshal(reqBody)
rb, err := json.Marshal(params)
if err != nil {
return nil, err
}
Expand All @@ -152,47 +133,40 @@ func (c *ClientEndpoint) Update(ctx context.Context, params Endpoint) (*Endpoint
req, err := http.NewRequestWithContext(
ctx,
"PATCH",
fmt.Sprintf("%s/%d", c.HostURL, params.ID),
fmt.Sprintf("%s/%s", c.HostURL, *params.ID),
strings.NewReader(string(rb)),
)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/merge-patch+json")

resp := &HttpResponse{}
endpoint := &Endpoint{}

resp, err = c.doRequest(req, resp)
err = c.doRequest(req, endpoint)
if err != nil {
return nil, err
}
if resp.Status != 200 {
return nil, fmt.Errorf("response status is %d", resp.Status)
}

return &params, nil
return endpoint, nil
}

// Delete endpoint by its ID
func (c *ClientEndpoint) Delete(ctx context.Context, id int) error {
func (c *ClientEndpoint) Delete(ctx context.Context, id string) error {
req, err := http.NewRequestWithContext(
ctx,
"DELETE",
fmt.Sprintf("%s/%d", c.HostURL, id),
fmt.Sprintf("%s/%s", c.HostURL, id),
nil,
)
if err != nil {
return err
}

resp := &HttpResponse{}

resp, err = c.doRequest(req, resp)
err = c.doRequest(req, nil)
if err != nil {
return err
}
if resp.Status != 204 {
return fmt.Errorf("response status is %d", resp.Status)
}

return nil
}
56 changes: 31 additions & 25 deletions datadome-client-go/client_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package datadome
import (
"context"
"fmt"
"math/rand"

"github.com/google/uuid"

Check failure on line 8 in datadome-client-go/client_mock.go

View workflow job for this annotation

GitHub Actions / test / acceptance tests

missing go.sum entry for module providing package github.com/google/uuid (imported by github.com/datadome/terraform-provider/datadome-client-go); to add:

Check failure on line 8 in datadome-client-go/client_mock.go

View workflow job for this annotation

GitHub Actions / test / acceptance tests

missing go.sum entry for module providing package github.com/google/uuid (imported by github.com/datadome/terraform-provider/datadome-client-go); to add:

Check failure on line 8 in datadome-client-go/client_mock.go

View workflow job for this annotation

GitHub Actions / lint / staticcheck

missing go.sum entry for module providing package github.com/google/uuid (imported by github.com/datadome/terraform-provider/datadome-client-go); to add:

Check failure on line 8 in datadome-client-go/client_mock.go

View workflow job for this annotation

GitHub Actions / test / unit tests

missing go.sum entry for module providing package github.com/google/uuid (imported by github.com/datadome/terraform-provider/datadome-client-go); to add:

Check failure on line 8 in datadome-client-go/client_mock.go

View workflow job for this annotation

GitHub Actions / test / unit tests

missing go.sum entry for module providing package github.com/google/uuid (imported by github.com/datadome/terraform-provider/datadome-client-go); to add:
)

// MockClientCustomRule structure for test purposes on the custom rules
Expand All @@ -28,13 +31,14 @@ func (m *MockClientCustomRule) Create(ctx context.Context, params CustomRule) (*
return m.CreateFunc(ctx, params)
}

if _, exists := m.resources[params.ID]; exists {
return nil, fmt.Errorf("resource already exists with ID %d", params.ID)
if params.ID == nil {
ID := rand.Int()
params.ID = &ID
}

newResource := &params
m.resources[newResource.ID] = newResource
return &newResource.ID, nil
m.resources[*newResource.ID] = newResource
return newResource.ID, nil
}

// Read mock method
Expand All @@ -45,7 +49,7 @@ func (m *MockClientCustomRule) Read(ctx context.Context, id int) (*CustomRule, e

var value *CustomRule
for _, v := range m.resources {
if v.ID == id {
if *v.ID == id {
value = v
}
}
Expand All @@ -59,12 +63,12 @@ func (m *MockClientCustomRule) Update(ctx context.Context, params CustomRule) (*
return m.UpdateFunc(ctx, params)
}

_, exists := m.resources[params.ID]
_, exists := m.resources[*params.ID]
if !exists {
return nil, fmt.Errorf("resource not found with ID %d", params.ID)
}

m.resources[params.ID] = &params
m.resources[*params.ID] = &params
return &params, nil
}

Expand All @@ -85,45 +89,47 @@ func (m *MockClientCustomRule) Delete(ctx context.Context, id int) error {

// MockClientEndpoint structure for test purposes on the endpoints
type MockClientEndpoint struct {
CreateFunc func(ctx context.Context, params Endpoint) (*int, error)
ReadFunc func(ctx context.Context) (*Endpoint, error)
CreateFunc func(ctx context.Context, params Endpoint) (*string, error)
ReadFunc func(ctx context.Context, id string) (*Endpoint, error)
UpdateFunc func(ctx context.Context, params Endpoint) (*Endpoint, error)
DeleteFunc func(ctx context.Context, id int) error
DeleteFunc func(ctx context.Context, id string) error

resources map[int]*Endpoint
resources map[string]*Endpoint
}

// NewMockClientCustomRule returns a new MockClient for custom rule management
func NewMockClientEndpoint() *MockClientEndpoint {
return &MockClientEndpoint{
resources: make(map[int]*Endpoint),
resources: make(map[string]*Endpoint),
}
}

// Create mock method
func (m *MockClientEndpoint) Create(ctx context.Context, params Endpoint) (*int, error) {
func (m *MockClientEndpoint) Create(ctx context.Context, params Endpoint) (*string, error) {
if m.CreateFunc != nil {
return m.CreateFunc(ctx, params)
}

if _, exists := m.resources[params.ID]; exists {
return nil, fmt.Errorf("resource already exists with ID %d", params.ID)
if params.ID == nil {
newUUID := uuid.New()
ID := newUUID.String()
params.ID = &ID
}

newResource := &params
m.resources[newResource.ID] = newResource
return &newResource.ID, nil
m.resources[*newResource.ID] = newResource
return newResource.ID, nil
}

// Read mock method
func (m *MockClientEndpoint) Read(ctx context.Context, id int) (*Endpoint, error) {
func (m *MockClientEndpoint) Read(ctx context.Context, id string) (*Endpoint, error) {
if m.ReadFunc != nil {
return m.ReadFunc(ctx)
return m.ReadFunc(ctx, id)
}

var value *Endpoint
for _, v := range m.resources {
if v.ID == id {
if *v.ID == id {
value = v
}
}
Expand All @@ -137,24 +143,24 @@ func (m *MockClientEndpoint) Update(ctx context.Context, params Endpoint) (*Endp
return m.UpdateFunc(ctx, params)
}

_, exists := m.resources[params.ID]
_, exists := m.resources[*params.ID]
if !exists {
return nil, fmt.Errorf("resource not found with ID %d", params.ID)
return nil, fmt.Errorf("resource not found with ID %s", *params.ID)
}

m.resources[params.ID] = &params
m.resources[*params.ID] = &params
return &params, nil
}

// Delete mock method
func (m *MockClientEndpoint) Delete(ctx context.Context, id int) error {
func (m *MockClientEndpoint) Delete(ctx context.Context, id string) error {
if m.DeleteFunc != nil {
return m.DeleteFunc(ctx, id)
}

_, exists := m.resources[id]
if !exists {
return fmt.Errorf("resource not found with ID %d", id)
return fmt.Errorf("resource not found with ID %s", id)
}

delete(m.resources, id)
Expand Down
2 changes: 2 additions & 0 deletions datadome-client-go/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/datadome/terraform-provider/datadome-client-go

go 1.22

require github.com/google/uuid v1.6.0
2 changes: 2 additions & 0 deletions datadome-client-go/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
4 changes: 2 additions & 2 deletions datadome-client-go/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type CustomRules struct {

// CustomRule structure containing the information of a custom rule
type CustomRule struct {
ID int `json:"id"`
ID *int `json:"id"`
Name string `json:"rule_name"`
Response string `json:"rule_response"`
Query string `json:"query"`
Expand All @@ -42,7 +42,7 @@ type CustomRule struct {

// Endpoint structure containing the information of an endpoint
type Endpoint struct {
ID int `json:"id"`
ID *string `json:"id,omitempty"`
Name string `json:"name"`
Description *string `json:"description,omitempty"`
PositionBefore *string `json:"positionBefore,omitempty"`
Expand Down
4 changes: 2 additions & 2 deletions datadome/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
)

type ProviderConfig struct {
ClientCustomRule common.API[datadome.CustomRule]
ClientEndpoint common.API[datadome.Endpoint]
ClientCustomRule common.API[datadome.CustomRule, int]

Check failure on line 13 in datadome/provider.go

View workflow job for this annotation

GitHub Actions / lint / golangci-lint

undefined: datadome (typecheck)
ClientEndpoint common.API[datadome.Endpoint, string]

Check failure on line 14 in datadome/provider.go

View workflow job for this annotation

GitHub Actions / lint / golangci-lint

undefined: datadome (typecheck)
}

// Provider of DataDome
Expand Down
Loading

0 comments on commit a407b4f

Please sign in to comment.