diff --git a/.changelog/1063.txt b/.changelog/1063.txt new file mode 100644 index 000000000..e27d99dd1 --- /dev/null +++ b/.changelog/1063.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +r2: Add support for listing R2 buckets +``` diff --git a/r2_bucket.go b/r2_bucket.go index d946b633d..08de630e1 100644 --- a/r2_bucket.go +++ b/r2_bucket.go @@ -2,6 +2,7 @@ package cloudflare import ( "context" + "encoding/json" "errors" "fmt" "net/http" @@ -11,6 +12,55 @@ var ( ErrMissingBucketName = errors.New("require bucket name missing") ) +// R2Bucket defines a container for objects stored in R2 Storage. +type R2Bucket struct { + Name string `json:"name"` + CreationDate string `json:"creation_date,omitempty"` +} + +// R2Buckets represents the map of buckets response from +// the R2 buckets endpoint. +type R2Buckets struct { + Buckets []R2Bucket `json:"buckets"` +} + +// R2BucketListResponse represents the response from the list +// R2 buckets endpoint. +type R2BucketListResponse struct { + Result R2Buckets `json:"result"` + Response +} + +type ListR2BucketsParams struct { + Name string `url:"name_contains,omitempty"` + StartAfter string `url:"start_after,omitempty"` + PerPage int64 `url:"per_page,omitempty"` + Order string `url:"order,omitempty"` + Direction string `url:"direction,omitempty"` + Cursor string `url:"cursor,omitempty"` +} + +// ListR2Buckets Lists R2 buckets. +func (api *API) ListR2Buckets(ctx context.Context, rc *ResourceContainer, params ListR2BucketsParams) ([]R2Bucket, error) { + if rc.Identifier == "" { + return []R2Bucket{}, ErrMissingAccountID + } + + uri := buildURI(fmt.Sprintf("/accounts/%s/r2/buckets", rc.Identifier), params) + res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return []R2Bucket{}, err + } + + var r2BucketListResponse R2BucketListResponse + err = json.Unmarshal(res, &r2BucketListResponse) + if err != nil { + return []R2Bucket{}, fmt.Errorf("%s: %w", errUnmarshalError, err) + } + + return r2BucketListResponse.Result.Buckets, nil +} + type CreateR2BucketParameters struct { Name string `json:"name,omitempty"` } diff --git a/r2_bucket_test.go b/r2_bucket_test.go index 92926d5e9..42168838c 100644 --- a/r2_bucket_test.go +++ b/r2_bucket_test.go @@ -11,6 +11,40 @@ import ( const testBucketName = "example-bucket" +func TestR2_ListBuckets(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc(fmt.Sprintf("/accounts/%s/r2/buckets", testAccountID), func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "buckets": [ + { + "name": "example-bucket", + "creation_date": "2022-06-24T19:58:49.477Z" + } + ] + } +}`) + }) + + want := []R2Bucket{ + { + Name: "example-bucket", + CreationDate: "2022-06-24T19:58:49.477Z", + }, + } + actual, err := client.ListR2Buckets(context.Background(), AccountIdentifier(testAccountID), ListR2BucketsParams{}) + if assert.NoError(t, err) { + assert.Equal(t, want, actual) + } +} + func TestR2_CreateBucket(t *testing.T) { setup() defer teardown()