DEV Community

Cover image for How to use Cloud flare R2 storage with workers API & S3 compatibility
Sanya_Lazy
Sanya_Lazy

Posted on

How to use Cloud flare R2 storage with workers API & S3 compatibility

Cloudflare R2 storage gives free cloud storage for startups and for personal use, but there are monthly usage limits. But it is still worth full.

⭐ Check this image (Reference link)

Cloudflare r2 pricing

⚙️Setup:

  • Ensure that Node.js is installed on your PC or laptop.
  • First, sign up for a Cloudflare account and provide your payment information (this is just to complete your profile; there's no charge as everything is free after account setup).

♨️Steps:

  • Create folder 📂 and navigate to that folder.
  • Install wrangler (reference link)
npm install wrangler --save-dev
Enter fullscreen mode Exit fullscreen mode
  • Login to your wrangler account using this
npx wrangler login
Enter fullscreen mode Exit fullscreen mode
  • Now Create a bucket in Cloudflare dashboard.
  • Navigate to Cloudflare and select R2 and create bucket.
  • Type a name for the bucket and click on "Create Bucket."
  • Navigate to bucket you created.
  • Now Upload your first Object (any image/video/). Choose either drag and drop or use file upload area.
  • Once the upload is complete, you will receive a confirmation message.
  • If can't understand (refer to this link)

Bucket Access options (Workers Runtime API)

  • Now create new application with C3.

C3 (create-cloudflare-cli) is a command-line utility created to assist you in quickly setting up and deploying Workers and Pages applications to Cloudflare.

  • To get started open terminal in folder. Run this
npm create cloudflare@latest
Enter fullscreen mode Exit fullscreen mode
  • Create your bucket by running this now
npx wrangler r2 bucket create <YOUR_BUCKET_NAME> #enter new bucket name
Enter fullscreen mode Exit fullscreen mode
  • To verify if the bucket has been created and to retrieve your list of buckets.

Bind your bucket to a worker (read carefully)

  • You need to bind your bucket to a worker, for using with API.

Bindings
A binding refers to the way your Worker connects with external resources like KV Namespaces, Durable Objects, or R2 Buckets. It acts as a runtime variable that the Workers environment supplies to your code.

You can specify a variable name in your wrangler.toml file, which will be linked to these resources during runtime, allowing you to interact with them through this variable. The variable name and its behavior for each binding are defined by you when deploying the Worker. For further details, consult the Environment Variables documentation.

  • A binding is specified in the wrangler.toml file located in your Worker project’s directory. Locate the newly created wrangler.toml file in your project directory and update the account_id field with your Cloudflare Account ID.
  • To find your Details, navigate

Next, find your Account ID by logging in to the Cloudflare dashboard > Overview > move down to API > and select Click to copy to copy your Account ID. Or run the wrangler whoami command [to copy your Account ID]- (reference link)

// wrangler.toml (file)
name = "<YOUR_WORKER_NAME>"
main = "src/index.js"
compatibility_date = "2022-06-30"

account_id = "YOUR_ACCOUNT_ID" # ← Replace with your Account ID.
workers_dev = true
Enter fullscreen mode Exit fullscreen mode

To connect your R2 bucket to your Worker, include the following in your wrangler.toml file:

  • Update the binding property to a valid JavaScript variable identifier.
  • Set the bucket_name to the <YOUR_BUCKET_NAME> that you used when creating your bucket.
[[r2_buckets]]
binding = 'MY_BUCKET' # <~ valid JavaScript variable name
bucket_name = '<YOUR_BUCKET_NAME>'
Enter fullscreen mode Exit fullscreen mode

Find more detailed information on configuring your Worker in the [Wrangler Configuration documentation]

Access your R2 bucket through your Worker:

  • Within your Worker code, your bucket is now accessible via the MY_BUCKET variable, allowing you to start interacting with it.

Local Development Mode in Wrangler

  • By default, wrangler dev operates in local development mode.
  • In this mode, all actions executed by your local Worker will use local storage on your machine.
  • If you want R2 operations performed during development to interact with a real R2 bucket, use wrangler dev --remote.

An R2 bucket supports operations to READ, LIST, WRITE, and DELETE objects. Below is an example demonstrating all these operations using the Module Worker syntax. Please add the following snippet to your project's index.js file: (If you need clarification on the complete code provided earlier, feel free to ask.)

// src/index.js

var hasValidHeader = (request, env) => {
    return request.headers.get("X-Custom-Auth-Key") === env.AUTH_KEY_SECRET;
  };

  function authorizeRequest(request, env, key) {
    switch (request.method) {
      case "PUT":
      case "DELETE":
        return hasValidHeader(request, env);
      case "GET":
        return true;
      default:
        return false;
    }
  }

  var src_default = {
    async fetch(request, env) {
      try {
        const url = new URL(request.url);
        console.log("Request URL:", url);
        const key = url.pathname.slice(1);
        if (!authorizeRequest(request, env, key)) {
          console.log("Authorization failed");
          return new Response("Forbidden", { status: 403 });
        }
        console.log("Authorization successful");
        switch (request.method) {
          case "PUT":
            console.log("Handling PUT request");
            // Parse the request body to extract fields
            const formData = await request.formData();
            const Filename = formData.get("Filename");
            const type = formData.get("type");
            const image = formData.get("image");

            // Perform image upload and handle additional fields
            await env.MY_BUCKET.put(key, image); // Assuming image is the binary image data
            console.log(`Uploaded ${Filename} successfully! Type: ${type}`);
            return new Response(`Uploaded ${Filename} successfully! Type: ${type}`);
          case "GET":
            console.log("Handling GET request");
            const object = await env.MY_BUCKET.get(key);
            if (object === null) {
              console.log("Object not found");
              return new Response("Object Not Found", { status: 404 });
            }
            const headers = new Headers();
            object.writeHttpMetadata(headers);
            headers.set("etag", object.httpEtag);
            return new Response(object.body, {
              headers
            });
          case "DELETE":
            console.log("Handling DELETE request");
            await env.MY_BUCKET.delete(key);
            return new Response("Deleted!");
          default:
            console.log("Invalid request method");
            return new Response("Method Not Allowed", {
              status: 405,
              headers: {
                Allow: "PUT, GET, DELETE"
              }
            });
        }
      } catch (error) {
        console.error("Error:", error);
        return new Response("Internal Server Error", { status: 500 });
      }
    }
  };

  export {
    src_default as default
  };

Enter fullscreen mode Exit fullscreen mode

Bucket access and Privacy (reference link)

  • Using custom headers we can allow or deny a request based on a known pre-shared key in a header.
  • You need to protect bucket operations.
  • For PUT and DELETE requests, you'll utilize a new environment variable called AUTH_KEY_SECRET, which will be defined later as a Wrangler secret.
  • For GET requests, you'll restrict access to a specific file. This logic is implemented within an authorizeRequest function, while the hasValidHeader function manages the custom header validation. If all checks are successful, the operation proceeds.
  • To use this, create a secret key via Wrangler.
  • Run this command
npx wrangler secret put AUTH_KEY_SECRET
Enter fullscreen mode Exit fullscreen mode
  • This command will ask you to input a secret in your terminal.
npx wrangler secret put AUTH_KEY_SECRET
#Enter the secret text you'd like assigned to the variable 
# AUTH_KEY_SECRET on the script named <YOUR_WORKER_NAME>:*********
# 🌀  Creating the secret for script name <YOUR_WORKER_NAME>✨  
# Success! Uploaded secret AUTH_KEY_SECRET.
Enter fullscreen mode Exit fullscreen mode
  • We use like this in URL (header)
X-Custom-Auth-Key - 123456789 (example code)
Enter fullscreen mode Exit fullscreen mode

This secret is now accessible as AUTH_KEY_SECRET in the env parameter of your Worker.

Deploy your bucket

  • Now that your Worker and Bucket are configured, execute this command in the terminal to deploy to Cloudflare's global network. (reference link)
npx wrangler deploy
Enter fullscreen mode Exit fullscreen mode
  • After deploying you get your worker url.

Testing

Now After Deploying, we can use like this:
I am showing in Postman, you can use any other API testing platforms.

using cloudflare api in postman

  • Ensure to include the Header. like this

adding header in cloudflare r2

  • Now when press send You get a Successful message, and you can check that file is uploaded to cloud flare R2 account.
  • Use different file names; using the same name will overwrite the existing image.
  • You can upload various file types, similar to the above.

To view uploaded image:

  • Simply append the file name to the end of your Cloudflare Worker URL to view the image. No header is required; just use URL/your-file-name.

Note: Ensure that you are using a Cloudflare account within the free limit. Exceeding this limit may result in charges. Stay within the free limit to avoid any worries.

GitHub Complete code (🔗)

Happy Coding 😴 - Be Lazy

Contact DM - Twitter(X)
Contact Mail - sanya.san@myyahoo.com

Top comments (0)