github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/edgeworkers/edgekv_items.go (about)

     1  package edgeworkers
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"net/http"
    11  
    12  	validation "github.com/go-ozzo/ozzo-validation/v4"
    13  )
    14  
    15  type (
    16  	// EdgeKVItems is EdgeKV Item API interface
    17  	EdgeKVItems interface {
    18  		// ListItems lists items in EdgeKV group
    19  		//
    20  		// See: https://techdocs.akamai.com/edgekv/reference/get-group-1
    21  		ListItems(context.Context, ListItemsRequest) (*ListItemsResponse, error)
    22  
    23  		// GetItem reads an item from EdgeKV group
    24  		//
    25  		// See: https://techdocs.akamai.com/edgekv/reference/get-item
    26  		GetItem(context.Context, GetItemRequest) (*Item, error)
    27  
    28  		// UpsertItem creates or updates an item in EdgeKV group
    29  		//
    30  		// See: https://techdocs.akamai.com/edgekv/reference/put-item
    31  		UpsertItem(context.Context, UpsertItemRequest) (*string, error)
    32  
    33  		// DeleteItem deletes an item from EdgeKV group
    34  		//
    35  		// See: https://techdocs.akamai.com/edgekv/reference/delete-item
    36  		DeleteItem(context.Context, DeleteItemRequest) (*string, error)
    37  	}
    38  
    39  	// ListItemsRequest represents the request params used to list items
    40  	ListItemsRequest struct {
    41  		ItemsRequestParams
    42  	}
    43  
    44  	// GetItemRequest represents the request params used to get a single item
    45  	GetItemRequest struct {
    46  		ItemID string
    47  		ItemsRequestParams
    48  	}
    49  
    50  	// UpsertItemRequest represents the request params and body used to create or update an item
    51  	UpsertItemRequest struct {
    52  		ItemID   string
    53  		ItemData Item
    54  		ItemsRequestParams
    55  	}
    56  
    57  	// DeleteItemRequest represents the request params used to delete an item
    58  	DeleteItemRequest struct {
    59  		ItemID string
    60  		ItemsRequestParams
    61  	}
    62  
    63  	// ItemsRequestParams represents the params used to list items
    64  	ItemsRequestParams struct {
    65  		Network     ItemNetwork
    66  		NamespaceID string
    67  		GroupID     string
    68  	}
    69  
    70  	// Item represents a single item
    71  	Item string
    72  
    73  	// ItemNetwork represents available item network types
    74  	ItemNetwork string
    75  
    76  	// ListItemsResponse represents the response from list items
    77  	ListItemsResponse []string
    78  )
    79  
    80  const (
    81  	// ItemStagingNetwork is the staging network
    82  	ItemStagingNetwork ItemNetwork = "staging"
    83  
    84  	// ItemProductionNetwork is the staging network
    85  	ItemProductionNetwork ItemNetwork = "production"
    86  )
    87  
    88  // Validate validates ItemsRequestParams
    89  func (r ItemsRequestParams) Validate() error {
    90  	return validation.Errors{
    91  		"Network": validation.Validate(r.Network, validation.Required, validation.In(ItemStagingNetwork, ItemProductionNetwork).Error(
    92  			fmt.Sprintf("value '%s' is invalid. Must be one of: '%s' or '%s'", r.Network, ItemStagingNetwork, ItemProductionNetwork))),
    93  		"NamespaceID": validation.Validate(r.NamespaceID, validation.Required),
    94  		"GroupID":     validation.Validate(r.GroupID, validation.Required),
    95  	}.Filter()
    96  }
    97  
    98  // Validate validates ListItemsRequest
    99  func (r ListItemsRequest) Validate() error {
   100  	return validation.Errors{
   101  		"ItemsRequestParams": validation.Validate(r.ItemsRequestParams, validation.Required),
   102  	}.Filter()
   103  }
   104  
   105  // Validate validates GetItemRequest
   106  func (r GetItemRequest) Validate() error {
   107  	return validation.Errors{
   108  		"ItemID":             validation.Validate(r.ItemID, validation.Required),
   109  		"ItemsRequestParams": validation.Validate(r.ItemsRequestParams, validation.Required),
   110  	}.Filter()
   111  }
   112  
   113  // Validate validates UpsertItemRequest
   114  func (r UpsertItemRequest) Validate() error {
   115  	return validation.Errors{
   116  		"ItemID":             validation.Validate(r.ItemID, validation.Required),
   117  		"ItemData":           validation.Validate(r.ItemData, validation.Required),
   118  		"ItemsRequestParams": validation.Validate(r.ItemsRequestParams, validation.Required),
   119  	}.Filter()
   120  }
   121  
   122  // Validate validates DeleteItemRequest
   123  func (r DeleteItemRequest) Validate() error {
   124  	return validation.Errors{
   125  		"ItemID":             validation.Validate(r.ItemID, validation.Required),
   126  		"ItemsRequestParams": validation.Validate(r.ItemsRequestParams, validation.Required),
   127  	}.Filter()
   128  }
   129  
   130  // IsJSON returns true if the given string is a valid json
   131  func IsJSON(str Item) bool {
   132  	var js json.RawMessage
   133  	return json.Unmarshal([]byte(str), &js) == nil
   134  }
   135  
   136  var (
   137  	// ErrListItems is returned in case an error occurs on ListItems operation
   138  	ErrListItems = errors.New("list items")
   139  	// ErrGetItem is returned in case an error occurs on GetItem operation
   140  	ErrGetItem = errors.New("get item")
   141  	// ErrUpsertItem is returned in case an error occurs on UpsertItem operation
   142  	ErrUpsertItem = errors.New("create or update item")
   143  	// ErrDeleteItem is returned in case an error occurs on DeleteItem operation
   144  	ErrDeleteItem = errors.New("delete item")
   145  )
   146  
   147  func (e *edgeworkers) ListItems(ctx context.Context, params ListItemsRequest) (*ListItemsResponse, error) {
   148  	logger := e.Log(ctx)
   149  	logger.Debug("ListItems")
   150  
   151  	if err := params.Validate(); err != nil {
   152  		return nil, fmt.Errorf("%s: %w: %s", ErrListItems, ErrStructValidation, err)
   153  	}
   154  
   155  	uri := fmt.Sprintf("/edgekv/v1/networks/%s/namespaces/%s/groups/%s", params.Network, params.NamespaceID, params.GroupID)
   156  
   157  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
   158  	if err != nil {
   159  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrListItems, err)
   160  	}
   161  
   162  	var result ListItemsResponse
   163  	resp, err := e.Exec(req, &result)
   164  	if err != nil {
   165  		return nil, fmt.Errorf("%w: request failed: %s", ErrListItems, err)
   166  	}
   167  
   168  	if resp.StatusCode != http.StatusOK {
   169  		return nil, fmt.Errorf("%s: %w", ErrListItems, e.Error(resp))
   170  	}
   171  
   172  	return &result, nil
   173  }
   174  
   175  func (e *edgeworkers) GetItem(ctx context.Context, params GetItemRequest) (*Item, error) {
   176  	logger := e.Log(ctx)
   177  	logger.Debug("GetItem")
   178  
   179  	if err := params.Validate(); err != nil {
   180  		return nil, fmt.Errorf("%s: %w: %s", ErrGetItem, ErrStructValidation, err)
   181  	}
   182  
   183  	uri := fmt.Sprintf("/edgekv/v1/networks/%s/namespaces/%s/groups/%s/items/%s", params.Network,
   184  		params.NamespaceID, params.GroupID, params.ItemID)
   185  
   186  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
   187  	if err != nil {
   188  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetItem, err)
   189  	}
   190  
   191  	resp, err := e.Exec(req, nil)
   192  	if err != nil {
   193  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetItem, err)
   194  	}
   195  
   196  	if resp.StatusCode != http.StatusOK {
   197  		return nil, fmt.Errorf("%s: %w", ErrGetItem, e.Error(resp))
   198  	}
   199  
   200  	data, err := ioutil.ReadAll(resp.Body)
   201  	if err != nil {
   202  		return nil, fmt.Errorf("%w: failed to fetch data: %s", ErrGetItem, err)
   203  	}
   204  
   205  	result := Item(data)
   206  	return &result, nil
   207  }
   208  
   209  func (e *edgeworkers) UpsertItem(ctx context.Context, params UpsertItemRequest) (*string, error) {
   210  	logger := e.Log(ctx)
   211  	logger.Debug("UpsertItem")
   212  
   213  	if err := params.Validate(); err != nil {
   214  		return nil, fmt.Errorf("%s: %w: %s", ErrUpsertItem, ErrStructValidation, err)
   215  	}
   216  
   217  	uri := fmt.Sprintf("/edgekv/v1/networks/%s/namespaces/%s/groups/%s/items/%s", params.Network,
   218  		params.NamespaceID, params.GroupID, params.ItemID)
   219  
   220  	data := []byte(params.ItemData)
   221  	req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, ioutil.NopCloser(bytes.NewBuffer(data)))
   222  	if err != nil {
   223  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrUpsertItem, err)
   224  	}
   225  	req.ContentLength = int64(len(data))
   226  
   227  	if !IsJSON(params.ItemData) {
   228  		req.Header.Set("Content-Type", "text/plain")
   229  	}
   230  
   231  	resp, err := e.Exec(req, nil)
   232  	if err != nil {
   233  		return nil, fmt.Errorf("%w: request failed: %s", ErrUpsertItem, err)
   234  	}
   235  
   236  	if resp.StatusCode != http.StatusOK {
   237  		return nil, fmt.Errorf("%s: %w", ErrUpsertItem, e.Error(resp))
   238  	}
   239  
   240  	data, err = ioutil.ReadAll(resp.Body)
   241  	if err != nil {
   242  		return nil, fmt.Errorf("%w: failed to fetch data: %s", ErrUpsertItem, err)
   243  	}
   244  
   245  	result := string(data)
   246  	return &result, nil
   247  }
   248  
   249  func (e *edgeworkers) DeleteItem(ctx context.Context, params DeleteItemRequest) (*string, error) {
   250  	logger := e.Log(ctx)
   251  	logger.Debug("DeleteItem")
   252  
   253  	if err := params.Validate(); err != nil {
   254  		return nil, fmt.Errorf("%s: %w: %s", ErrDeleteItem, ErrStructValidation, err)
   255  	}
   256  
   257  	uri := fmt.Sprintf("/edgekv/v1/networks/%s/namespaces/%s/groups/%s/items/%s", params.Network,
   258  		params.NamespaceID, params.GroupID, params.ItemID)
   259  
   260  	req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri, nil)
   261  	if err != nil {
   262  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrDeleteItem, err)
   263  	}
   264  
   265  	resp, err := e.Exec(req, nil)
   266  	if err != nil {
   267  		return nil, fmt.Errorf("%w: request failed: %s", ErrDeleteItem, err)
   268  	}
   269  
   270  	if resp.StatusCode != http.StatusOK {
   271  		return nil, fmt.Errorf("%s: %w", ErrDeleteItem, e.Error(resp))
   272  	}
   273  
   274  	data, err := ioutil.ReadAll(resp.Body)
   275  	if err != nil {
   276  		return nil, fmt.Errorf("%w: failed to fetch data: %s", ErrDeleteItem, err)
   277  	}
   278  
   279  	var result = string(data)
   280  	return &result, nil
   281  }