Create the GET endpoint

Import the APIRoute type from "astro" and create a GET endpoint that accepts the locals parameter.

The locals object provides access to runtime environment variables and bindings, including the CLOUD_FILES binding that you'll use to interact with object storage.

Get the bucket and validate configuration

Access the CLOUD_FILES binding from locals.runtime.env and validate that the bucket is properly configured.

If the bucket isn't available, return a 500 error with a descriptive message to help with debugging.

List files with pagination support

Use the .list() method to retrieve files from the bucket.

The method returns an R2Object list with pagination support. Set a limit of 500 files per request to balance performance and memory usage. The response includes a truncated flag indicating if more files are available, and a cursor for pagination.

Key concepts:

  • Pagination: Buckets may contain thousands of files, so you use pagination to retrieve them in manageable chunks
  • Cursor-based pagination: Each response includes a cursor that points to the next page of results

Return the files as JSON

Return the complete list of files as a JSON response with proper headers. The listed.objects array contains all the files from the bucket, including metadata like file names, sizes, and creation dates.

Response format: The returned JSON will contain an array of R2Object items, each with properties like:

  • key: The file name/path
  • size: File size in bytes
  • etag: Entity tag for caching
  • httpEtag: HTTP-compatible entity tag
  • uploaded: Upload timestamp
  • checksums: File integrity checksums
  • httpMetadata: HTTP headers and metadata
list.ts
ExpandClose
1
import type { APIRoute } from "astro";
2

3
export const GET: APIRoute = async ({ request, locals }) => {
4
try {
5
// Check if bucket is available
6
const bucket = locals.runtime.env.CLOUD_FILES;
7
if (!bucket) {
8
return new Response("Cloud storage not configured", { status: 500 });
9
}
10

11
const options = { limit: 500 };
12
const listed = await bucket.list(options);
13
let truncated = listed.truncated;
14

15
// Paging through the files
16
// @ts-ignore
17
let cursor = truncated ? listed.cursor : undefined;
18

19
while (truncated) {
20
const next = await bucket.list({
21
...options,
22
cursor: cursor,
23
});
24
listed.objects.push(...next.objects);
25

26
truncated = next.truncated;
27
// @ts-ignore
28
cursor = next.cursor;
29
}
30

31
// Return the files as a JSON object
32
return new Response(JSON.stringify(listed.objects), {
33
headers: { "Content-Type": "application/json" },
34
});
35
} catch (error) {
36
console.error("Error listing assets:", error);
37
return new Response("Failed to list assets", { status: 500 });
38
}
39
};