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 }