github.com/fastly/go-fastly/v5@v5.3.0/fastly/dictionary_item.go (about)

     1  package fastly
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"sort"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/peterhellberg/link"
    11  )
    12  
    13  // DictionaryItem represents a dictionary item response from the Fastly API.
    14  type DictionaryItem struct {
    15  	ServiceID    string `mapstructure:"service_id"`
    16  	DictionaryID string `mapstructure:"dictionary_id"`
    17  	ItemKey      string `mapstructure:"item_key"`
    18  
    19  	ItemValue string     `mapstructure:"item_value"`
    20  	CreatedAt *time.Time `mapstructure:"created_at"`
    21  	UpdatedAt *time.Time `mapstructure:"updated_at"`
    22  	DeletedAt *time.Time `mapstructure:"deleted_at"`
    23  }
    24  
    25  // dictionaryItemsByKey is a sortable list of dictionary items.
    26  type dictionaryItemsByKey []*DictionaryItem
    27  
    28  // Len, Swap, and Less implement the sortable interface.
    29  func (s dictionaryItemsByKey) Len() int      { return len(s) }
    30  func (s dictionaryItemsByKey) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    31  func (s dictionaryItemsByKey) Less(i, j int) bool {
    32  	return s[i].ItemKey < s[j].ItemKey
    33  }
    34  
    35  // ListDictionaryItemsInput is used as input to the ListDictionaryItems function.
    36  type ListDictionaryItemsInput struct {
    37  	// ServiceID is the ID of the service (required).
    38  	ServiceID string
    39  
    40  	// DictionaryID is the ID of the dictionary to retrieve items for (required).
    41  	DictionaryID string
    42  	Direction    string
    43  	PerPage      int
    44  	Page         int
    45  	Sort         string
    46  }
    47  
    48  // ListDictionaryItems returns a list of items for a dictionary
    49  func (c *Client) ListDictionaryItems(i *ListDictionaryItemsInput) ([]*DictionaryItem, error) {
    50  	if i.ServiceID == "" {
    51  		return nil, ErrMissingServiceID
    52  	}
    53  
    54  	if i.DictionaryID == "" {
    55  		return nil, ErrMissingDictionaryID
    56  	}
    57  
    58  	path := fmt.Sprintf("/service/%s/dictionary/%s/items", i.ServiceID, i.DictionaryID)
    59  	resp, err := c.Get(path, nil)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  
    64  	var bs []*DictionaryItem
    65  	if err := decodeBodyMap(resp.Body, &bs); err != nil {
    66  		return nil, err
    67  	}
    68  	sort.Stable(dictionaryItemsByKey(bs))
    69  	return bs, nil
    70  }
    71  
    72  type ListDictionaryItemsPaginator struct {
    73  	consumed    bool
    74  	CurrentPage int
    75  	NextPage    int
    76  	LastPage    int
    77  	client      *Client
    78  	options     *ListDictionaryItemsInput
    79  }
    80  
    81  // HasNext returns a boolean indicating whether more pages are available
    82  func (p *ListDictionaryItemsPaginator) HasNext() bool {
    83  	return !p.consumed || p.Remaining() != 0
    84  }
    85  
    86  // Remaining returns the remaining page count
    87  func (p *ListDictionaryItemsPaginator) Remaining() int {
    88  	if p.LastPage == 0 {
    89  		return 0
    90  	}
    91  	return p.LastPage - p.CurrentPage
    92  }
    93  
    94  // GetNext retrieves data in the next page
    95  func (p *ListDictionaryItemsPaginator) GetNext() ([]*DictionaryItem, error) {
    96  	return p.client.listDictionaryItemsWithPage(p.options, p)
    97  }
    98  
    99  // NewListDictionaryItemsPaginator returns a new ListDictionaryItemsPaginator
   100  func (c *Client) NewListDictionaryItemsPaginator(i *ListDictionaryItemsInput) *ListDictionaryItemsPaginator {
   101  	return &ListDictionaryItemsPaginator{
   102  		client:  c,
   103  		options: i,
   104  	}
   105  }
   106  
   107  // listDictionaryItemsWithPage returns a list of items for a dictionary of a given page
   108  func (c *Client) listDictionaryItemsWithPage(i *ListDictionaryItemsInput, p *ListDictionaryItemsPaginator) ([]*DictionaryItem, error) {
   109  	if i.ServiceID == "" {
   110  		return nil, ErrMissingServiceID
   111  	}
   112  
   113  	if i.DictionaryID == "" {
   114  		return nil, ErrMissingDictionaryID
   115  	}
   116  
   117  	var perPage int
   118  	const maxPerPage = 100
   119  	if i.PerPage <= 0 {
   120  		perPage = maxPerPage
   121  	} else {
   122  		perPage = i.PerPage
   123  	}
   124  
   125  	if i.Page <= 0 && p.CurrentPage == 0 {
   126  		p.CurrentPage = 1
   127  	} else {
   128  		p.CurrentPage = p.CurrentPage + 1
   129  	}
   130  
   131  	path := fmt.Sprintf("/service/%s/dictionary/%s/items", i.ServiceID, i.DictionaryID)
   132  	requestOptions := &RequestOptions{
   133  		Params: map[string]string{
   134  			"per_page": strconv.Itoa(perPage),
   135  			"page":     strconv.Itoa(p.CurrentPage),
   136  		},
   137  	}
   138  
   139  	if i.Direction != "" {
   140  		requestOptions.Params["direction"] = i.Direction
   141  	}
   142  	if i.Sort != "" {
   143  		requestOptions.Params["sort"] = i.Sort
   144  	}
   145  
   146  	resp, err := c.Get(path, requestOptions)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	for _, l := range link.ParseResponse(resp) {
   152  		// indicates the Link response header contained the next page instruction
   153  		if l.Rel == "next" {
   154  			u, _ := url.Parse(l.URI)
   155  			query := u.Query()
   156  			p.NextPage, _ = strconv.Atoi(query["page"][0])
   157  		}
   158  		// indicates the Link response header contained the last page instruction
   159  		if l.Rel == "last" {
   160  			u, _ := url.Parse(l.URI)
   161  			query := u.Query()
   162  			p.LastPage, _ = strconv.Atoi(query["page"][0])
   163  		}
   164  	}
   165  
   166  	p.consumed = true
   167  
   168  	var bs []*DictionaryItem
   169  	if err := decodeBodyMap(resp.Body, &bs); err != nil {
   170  		return nil, err
   171  	}
   172  	sort.Stable(dictionaryItemsByKey(bs))
   173  
   174  	return bs, nil
   175  }
   176  
   177  // CreateDictionaryItemInput is used as input to the CreateDictionaryItem function.
   178  type CreateDictionaryItemInput struct {
   179  	// ServiceID is the ID of the service (required).
   180  	ServiceID string
   181  
   182  	// DictionaryID is the ID of the dictionary to retrieve items for (required).
   183  	DictionaryID string
   184  
   185  	ItemKey   string `url:"item_key,omitempty"`
   186  	ItemValue string `url:"item_value,omitempty"`
   187  }
   188  
   189  // CreateDictionaryItem creates a new Fastly dictionary item.
   190  func (c *Client) CreateDictionaryItem(i *CreateDictionaryItemInput) (*DictionaryItem, error) {
   191  	if i.ServiceID == "" {
   192  		return nil, ErrMissingServiceID
   193  	}
   194  
   195  	if i.DictionaryID == "" {
   196  		return nil, ErrMissingDictionaryID
   197  	}
   198  
   199  	path := fmt.Sprintf("/service/%s/dictionary/%s/item", i.ServiceID, i.DictionaryID)
   200  	resp, err := c.PostForm(path, i, nil)
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  
   205  	var b *DictionaryItem
   206  	if err := decodeBodyMap(resp.Body, &b); err != nil {
   207  		return nil, err
   208  	}
   209  	return b, nil
   210  }
   211  
   212  // CreateDictionaryItems creates new Fastly dictionary items from a slice.
   213  func (c *Client) CreateDictionaryItems(i []CreateDictionaryItemInput) ([]DictionaryItem, error) {
   214  
   215  	var b []DictionaryItem
   216  	for _, cdii := range i {
   217  		di, err := c.CreateDictionaryItem(&cdii)
   218  		if err != nil {
   219  			return nil, err
   220  		}
   221  		b = append(b, *di)
   222  	}
   223  	return b, nil
   224  }
   225  
   226  // GetDictionaryItemInput is used as input to the GetDictionaryItem function.
   227  type GetDictionaryItemInput struct {
   228  	// ServiceID is the ID of the service (required).
   229  	ServiceID string
   230  
   231  	// DictionaryID is the ID of the dictionary to retrieve items for (required).
   232  	DictionaryID string
   233  
   234  	// ItemKey is the name of the dictionary item to fetch.
   235  	ItemKey string
   236  }
   237  
   238  // GetDictionaryItem gets the dictionary item with the given parameters.
   239  func (c *Client) GetDictionaryItem(i *GetDictionaryItemInput) (*DictionaryItem, error) {
   240  	if i.ServiceID == "" {
   241  		return nil, ErrMissingServiceID
   242  	}
   243  
   244  	if i.DictionaryID == "" {
   245  		return nil, ErrMissingDictionaryID
   246  	}
   247  
   248  	if i.ItemKey == "" {
   249  		return nil, ErrMissingItemKey
   250  	}
   251  
   252  	path := fmt.Sprintf("/service/%s/dictionary/%s/item/%s", i.ServiceID, i.DictionaryID, url.PathEscape(i.ItemKey))
   253  	resp, err := c.Get(path, nil)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	var b *DictionaryItem
   259  	if err := decodeBodyMap(resp.Body, &b); err != nil {
   260  		return nil, err
   261  	}
   262  	return b, nil
   263  }
   264  
   265  // UpdateDictionaryItemInput is used as input to the UpdateDictionaryItem function.
   266  type UpdateDictionaryItemInput struct {
   267  	// ServiceID is the ID of the service (required).
   268  	ServiceID string
   269  
   270  	// DictionaryID is the ID of the dictionary to retrieve items for (required).
   271  	DictionaryID string
   272  
   273  	// ItemKey is the name of the dictionary item to fetch (required).
   274  	ItemKey string
   275  
   276  	// ItemValue is the new value of the dictionary item (required).
   277  	ItemValue string `url:"item_value"`
   278  }
   279  
   280  // UpdateDictionaryItem updates a specific dictionary item.
   281  func (c *Client) UpdateDictionaryItem(i *UpdateDictionaryItemInput) (*DictionaryItem, error) {
   282  	if i.ServiceID == "" {
   283  		return nil, ErrMissingServiceID
   284  	}
   285  
   286  	if i.DictionaryID == "" {
   287  		return nil, ErrMissingDictionaryID
   288  	}
   289  
   290  	if i.ItemKey == "" {
   291  		return nil, ErrMissingItemKey
   292  	}
   293  
   294  	path := fmt.Sprintf("/service/%s/dictionary/%s/item/%s", i.ServiceID, i.DictionaryID, url.PathEscape(i.ItemKey))
   295  	resp, err := c.PutForm(path, i, nil)
   296  	if err != nil {
   297  		return nil, err
   298  	}
   299  
   300  	var b *DictionaryItem
   301  	if err := decodeBodyMap(resp.Body, &b); err != nil {
   302  		return nil, err
   303  	}
   304  	return b, nil
   305  }
   306  
   307  type BatchModifyDictionaryItemsInput struct {
   308  	// ServiceID is the ID of the service (required).
   309  	ServiceID string `json:"-"`
   310  
   311  	// DictionaryID is the ID of the dictionary to modify items for (required).
   312  	DictionaryID string `json:"-"`
   313  
   314  	Items []*BatchDictionaryItem `json:"items"`
   315  }
   316  
   317  type BatchDictionaryItem struct {
   318  	Operation BatchOperation `json:"op"`
   319  	ItemKey   string         `json:"item_key"`
   320  	ItemValue string         `json:"item_value"`
   321  }
   322  
   323  func (c *Client) BatchModifyDictionaryItems(i *BatchModifyDictionaryItemsInput) error {
   324  
   325  	if i.ServiceID == "" {
   326  		return ErrMissingServiceID
   327  	}
   328  
   329  	if i.DictionaryID == "" {
   330  		return ErrMissingDictionaryID
   331  	}
   332  
   333  	if len(i.Items) > BatchModifyMaximumOperations {
   334  		return ErrMaxExceededItems
   335  	}
   336  
   337  	path := fmt.Sprintf("/service/%s/dictionary/%s/items", i.ServiceID, i.DictionaryID)
   338  	resp, err := c.PatchJSON(path, i, nil)
   339  	if err != nil {
   340  		return err
   341  	}
   342  
   343  	var batchModifyResult map[string]string
   344  	if err := decodeBodyMap(resp.Body, &batchModifyResult); err != nil {
   345  		return err
   346  	}
   347  
   348  	return nil
   349  }
   350  
   351  // DeleteDictionaryItemInput is the input parameter to DeleteDictionaryItem.
   352  type DeleteDictionaryItemInput struct {
   353  	// ServiceID is the ID of the service (required).
   354  	ServiceID string
   355  
   356  	// DictionaryID is the ID of the dictionary to retrieve items for (required).
   357  	DictionaryID string
   358  
   359  	// ItemKey is the name of the dictionary item to delete.
   360  	ItemKey string
   361  }
   362  
   363  // DeleteDictionaryItem deletes the given dictionary item.
   364  func (c *Client) DeleteDictionaryItem(i *DeleteDictionaryItemInput) error {
   365  	if i.ServiceID == "" {
   366  		return ErrMissingServiceID
   367  	}
   368  
   369  	if i.DictionaryID == "" {
   370  		return ErrMissingDictionaryID
   371  	}
   372  
   373  	if i.ItemKey == "" {
   374  		return ErrMissingItemKey
   375  	}
   376  
   377  	path := fmt.Sprintf("/service/%s/dictionary/%s/item/%s", i.ServiceID, i.DictionaryID, url.PathEscape(i.ItemKey))
   378  	resp, err := c.Delete(path, nil)
   379  	if err != nil {
   380  		return err
   381  	}
   382  	defer resp.Body.Close()
   383  
   384  	// Unlike other endpoints, the dictionary endpoint does not return a status
   385  	// response - it just returns a 200 OK.
   386  	return nil
   387  }