asset.ts

_27
import type { APIRoute } from "astro";
_27
_27
export const GET: APIRoute = async ({ request, locals }) => {
_27
// Get the key from the request
_27
const url = new URL(request.url);
_27
const key = url.searchParams.get("key");
_27
if (!key) {
_27
return new Response("Missing key", { status: 400 });
_27
}
_27
_27
// Get the object from the bucket
_27
const bucket = locals.runtime.env.CLOUD_FILES;
_27
const object = await bucket.get(key as string);
_27
if (!object) {
_27
return new Response("Not found", { status: 404 });
_27
}
_27
_27
// Get the data from the object and return it
_27
const data = await object.arrayBuffer();
_27
const contentType = object.httpMetadata?.contentType ?? "";
_27
_27
return new Response(data, {
_27
headers: {
_27
"Content-Type": contentType,
_27
},
_27
});
_27
};

Create the GET endpoint

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

This endpoint will serve individual files from the bucket based on the file key provided in the URL query parameters.

Get the file key from the request

Extract the file key from the URL query parameters using url.searchParams.get("key"). The key represents the file name or path within the bucket.

Validate that a key is provided - if missing, return a 400 Bad Request error with a descriptive message to help with debugging.

asset.ts

_27
import type { APIRoute } from "astro";
_27
_27
export const GET: APIRoute = async ({ request, locals }) => {
_27
// Get the key from the request
_27
const url = new URL(request.url);
_27
const key = url.searchParams.get("key");
_27
if (!key) {
_27
return new Response("Missing key", { status: 400 });
_27
}
_27
_27
// Get the object from the bucket
_27
const bucket = locals.runtime.env.CLOUD_FILES;
_27
const object = await bucket.get(key as string);
_27
if (!object) {
_27
return new Response("Not found", { status: 404 });
_27
}
_27
_27
// Get the data from the object and return it
_27
const data = await object.arrayBuffer();
_27
const contentType = object.httpMetadata?.contentType ?? "";
_27
_27
return new Response(data, {
_27
headers: {
_27
"Content-Type": contentType,
_27
},
_27
});
_27
};

Retrieve the object from the bucket

Access the CLOUD_FILES binding and use the .get() method to retrieve the specific file from the bucket using the provided key.

The method returns an R2Object if the file exists, or null if not found.

asset.ts

_27
import type { APIRoute } from "astro";
_27
_27
export const GET: APIRoute = async ({ request, locals }) => {
_27
// Get the key from the request
_27
const url = new URL(request.url);
_27
const key = url.searchParams.get("key");
_27
if (!key) {
_27
return new Response("Missing key", { status: 400 });
_27
}
_27
_27
// Get the object from the bucket
_27
const bucket = locals.runtime.env.CLOUD_FILES;
_27
const object = await bucket.get(key as string);
_27
if (!object) {
_27
return new Response("Not found", { status: 404 });
_27
}
_27
_27
// Get the data from the object and return it
_27
const data = await object.arrayBuffer();
_27
const contentType = object.httpMetadata?.contentType ?? "";
_27
_27
return new Response(data, {
_27
headers: {
_27
"Content-Type": contentType,
_27
},
_27
});
_27
};

Key concepts:

  • Bucket access: The CLOUD_FILES binding provides direct access to the bucket
  • Object retrieval: The .get() method is the primary way to fetch individual files

Extract data and metadata from the object

Convert the R2Object to a usable format using the .arrayBuffer() method, which returns the file data as a Uint8Array. Extract the content type from the object's httpMetadata property, with a fallback to an empty string if not available.

asset.ts

_27
import type { APIRoute } from "astro";
_27
_27
export const GET: APIRoute = async ({ request, locals }) => {
_27
// Get the key from the request
_27
const url = new URL(request.url);
_27
const key = url.searchParams.get("key");
_27
if (!key) {
_27
return new Response("Missing key", { status: 400 });
_27
}
_27
_27
// Get the object from the bucket
_27
const bucket = locals.runtime.env.CLOUD_FILES;
_27
const object = await bucket.get(key as string);
_27
if (!object) {
_27
return new Response("Not found", { status: 404 });
_27
}
_27
_27
// Get the data from the object and return it
_27
const data = await object.arrayBuffer();
_27
const contentType = object.httpMetadata?.contentType ?? "";
_27
_27
return new Response(data, {
_27
headers: {
_27
"Content-Type": contentType,
_27
},
_27
});
_27
};

Return the file with proper headers

Create a new Response object with the file data and set the Content-Type header to match the file's content type. This ensures browsers and clients can properly handle the file based on its type.

asset.ts

_27
import type { APIRoute } from "astro";
_27
_27
export const GET: APIRoute = async ({ request, locals }) => {
_27
// Get the key from the request
_27
const url = new URL(request.url);
_27
const key = url.searchParams.get("key");
_27
if (!key) {
_27
return new Response("Missing key", { status: 400 });
_27
}
_27
_27
// Get the object from the bucket
_27
const bucket = locals.runtime.env.CLOUD_FILES;
_27
const object = await bucket.get(key as string);
_27
if (!object) {
_27
return new Response("Not found", { status: 404 });
_27
}
_27
_27
// Get the data from the object and return it
_27
const data = await object.arrayBuffer();
_27
const contentType = object.httpMetadata?.contentType ?? "";
_27
_27
return new Response(data, {
_27
headers: {
_27
"Content-Type": contentType,
_27
},
_27
});
_27
};

Create the GET endpoint

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

This endpoint will serve individual files from the bucket based on the file key provided in the URL query parameters.

Get the file key from the request

Extract the file key from the URL query parameters using url.searchParams.get("key"). The key represents the file name or path within the bucket.

Validate that a key is provided - if missing, return a 400 Bad Request error with a descriptive message to help with debugging.

Retrieve the object from the bucket

Access the CLOUD_FILES binding and use the .get() method to retrieve the specific file from the bucket using the provided key.

The method returns an R2Object if the file exists, or null if not found.

Key concepts:

  • Bucket access: The CLOUD_FILES binding provides direct access to the bucket
  • Object retrieval: The .get() method is the primary way to fetch individual files

Extract data and metadata from the object

Convert the R2Object to a usable format using the .arrayBuffer() method, which returns the file data as a Uint8Array. Extract the content type from the object's httpMetadata property, with a fallback to an empty string if not available.

Return the file with proper headers

Create a new Response object with the file data and set the Content-Type header to match the file's content type. This ensures browsers and clients can properly handle the file based on its type.

asset.ts
ExpandClose

_27
import type { APIRoute } from "astro";
_27
_27
export const GET: APIRoute = async ({ request, locals }) => {
_27
// Get the key from the request
_27
const url = new URL(request.url);
_27
const key = url.searchParams.get("key");
_27
if (!key) {
_27
return new Response("Missing key", { status: 400 });
_27
}
_27
_27
// Get the object from the bucket
_27
const bucket = locals.runtime.env.CLOUD_FILES;
_27
const object = await bucket.get(key as string);
_27
if (!object) {
_27
return new Response("Not found", { status: 404 });
_27
}
_27
_27
// Get the data from the object and return it
_27
const data = await object.arrayBuffer();
_27
const contentType = object.httpMetadata?.contentType ?? "";
_27
_27
return new Response(data, {
_27
headers: {
_27
"Content-Type": contentType,
_27
},
_27
});
_27
};