Cloudflare এর হাতেখড়ি (পর্ব ৬) – Workers + Firebase একসাথে ব্যবহার

Cloudflare Workers ও Firebase একসাথে ব্যবহার

এতদিন Firebase এর হাতেখড়ি সিরিজে আমরা ফ্রন্টএন্ড থেকে সরাসরি Firebase SDK ব্যবহার করেছি — Security Rules দিয়ে সুরক্ষিত। কিন্তু কিছু কাজ আছে যা ফ্রন্টএন্ড থেকে করা ঠিক না — যেমন Security Rules বাইপাস করে পুরো ডেটাবেজ অ্যাক্সেস করা, বা একটা সিক্রেট থার্ড-পার্টি API-এর সাথে Firebase ডেটা মেলানো। এই পর্বে শিখব Cloudflare Worker থেকে Firebase-এর সাথে নিরাপদে কথা বলা।

কেন Worker থেকে Firebase দরকার হতে পারে

  • Admin-level অ্যাক্সেস — Security Rules উপেক্ষা করে সরাসরি পূর্ণ অ্যাক্সেস দরকার হলে (Firebase এর হাতেখড়ি পর্ব ১১-এ Cloud Functions-এ যেমন firebase-admin ব্যবহার করেছিলাম, এখানে Worker দিয়েও একই কাজ করা যায়)
  • একাধিক সার্ভিস মেলানো — যেমন একটা পেমেন্ট গেটওয়ে থেকে রেসপন্স পেয়ে Firebase-এ ডেটা আপডেট করা
  • Rate limiting ও ক্যাশিং — RTDB-তে বারবার একই রিকোয়েস্ট না পাঠিয়ে Worker-এ ক্যাশ করে রাখা

মনে রাখা জরুরি: সাধারণ Auth, Read, Write-এর জন্য ফ্রন্টএন্ড SDK + Security Rules-ই যথেষ্ট (Firebase এর হাতেখড়ি পর্ব ৮)। Worker দিয়ে Firebase অ্যাক্সেস শুধু তখনই দরকার যখন সত্যিই সার্ভার-সাইড নিয়ন্ত্রণ লাগে।

পদ্ধতি — REST API দিয়ে RTDB অ্যাক্সেস

Cloudflare Workers-এ Node.js-এর মতো সব npm প্যাকেজ সরাসরি চলে না (Workers একটা ভিন্ন runtime, V8 isolate-ভিত্তিক)। তাই সবচেয়ে সহজ ও নির্ভরযোগ্য পদ্ধতি হলো — Firebase-এর REST API সরাসরি fetch() দিয়ে কল করা।

RTDB-এর REST API খুবই সহজ — যেকোনো path-এর শেষে .json যোগ করলেই সেটা একটা সাধারণ HTTP endpoint হয়ে যায়।

// Worker থেকে বই তালিকা পড়া
export default {
  async fetch(request, env, ctx) {
    const dbUrl = "https://my-first-app-default-rtdb.firebasedatabase.app/books.json";

    const response = await fetch(dbUrl);
    const books = await response.json();

    return new Response(JSON.stringify(books), {
      headers: { "content-type": "application/json" },
    });
  },
};

লক্ষ্য করুন — এটা ঠিক পর্ব ৫-এর fetch()-ভিত্তিক প্যাটার্নেরই একটা প্রয়োগ, শুধু এবার URL-টা Firebase-এর।

Admin অ্যাক্সেস — Secret দিয়ে প্রমাণীকরণ

উপরের কোড শুধু তখনই কাজ করবে যদি সেই path-এর Security Rules-এ পাবলিক read থাকে (পর্ব ৮-এর ".read": true)। যদি Rules বাইপাস করে পূর্ণ অ্যাক্সেস দরকার হয়, তাহলে RTDB-এর একটা Database Secret লাগবে।

  1. Firebase Console-এ Project Settings → Service Accounts → Database secrets-এ যান (পুরনো লিগ্যাসি সিস্টেম, তবে Worker-এর জন্য সহজ)
  2. একটা সিক্রেট জেনারেট করুন, কপি করে রাখুন
  3. রিকোয়েস্টের URL-এ ?auth= প্যারামিটার হিসেবে যোগ করুন
export default {
  async fetch(request, env, ctx) {
    const dbUrl = `https://my-first-app-default-rtdb.firebasedatabase.app/books.json?auth=${env.FIREBASE_DB_SECRET}`;

    const response = await fetch(dbUrl, {
      method: "POST",
      body: JSON.stringify({ title: "নতুন বই", ownerId: "admin" }),
    });

    const result = await response.json();
    return new Response(JSON.stringify(result), {
      headers: { "content-type": "application/json" },
    });
  },
};

এখানে env.FIREBASE_DB_SECRET — এটাই এই পর্বের সবচেয়ে গুরুত্বপূর্ণ অংশ, কারণ এই সিক্রেট কখনো কোডে সরাসরি লেখা যাবে না।

সিক্রেট নিরাপদে সংরক্ষণ করা

Worker-এর নিজস্ব সিক্রেট ম্যানেজমেন্ট সিস্টেম আছে — GitHub Secrets-এর (পর্ব ২) মতোই ধারণা, কিন্তু Cloudflare-এর নিজের জায়গায়।

# টার্মিনাল থেকে সিক্রেট যোগ করা
wrangler secret put FIREBASE_DB_SECRET

# একটা প্রম্পট আসবে, সেখানে সিক্রেট মান পেস্ট করলেই এনক্রিপ্টেড হয়ে সেভ হয়

এই সিক্রেট Cloudflare-এর সার্ভারে এনক্রিপ্টেড থাকে, কোডে বা Git হিস্টোরিতে কখনো দেখা যায় না — শুধু env.FIREBASE_DB_SECRET দিয়ে রানটাইমে অ্যাক্সেস করা যায়।

বাস্তব উদাহরণ — একটা প্রক্সি API

একটা সম্পূর্ণ উদাহরণ — Worker একটা "middle-man" হিসেবে কাজ করছে, ফ্রন্টএন্ড থেকে সরাসরি Firebase Database Secret কখনো এক্সপোজ না করেই।

const corsHeaders = {
  "Access-Control-Allow-Origin": "https://arifstack.com",
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
};

export default {
  async fetch(request, env, ctx) {
    if (request.method === "OPTIONS") {
      return new Response(null, { headers: corsHeaders });
    }

    const url = new URL(request.url);

    if (url.pathname === "/api/admin-books" && request.method === "GET") {
      const dbUrl = `https://my-first-app-default-rtdb.firebasedatabase.app/books.json?auth=${env.FIREBASE_DB_SECRET}`;
      const res = await fetch(dbUrl);
      const books = await res.json();

      return new Response(JSON.stringify(books), {
        headers: { "content-type": "application/json", ...corsHeaders },
      });
    }

    return new Response("পেজ পাওয়া যায়নি", { status: 404, headers: corsHeaders });
  },
};

এখানে পর্ব ৫-এর রুটিং, CORS হেডার, আর এই পর্বের সিক্রেট-ভিত্তিক Firebase কল — সবকিছু একসাথে জোড়া লেগেছে।

ইন্টারেক্টিভ — Proxy Flow দেখো

নিচে দেখো ফ্রন্টএন্ড থেকে Worker হয়ে Firebase পর্যন্ত রিকোয়েস্ট কীভাবে যায়, আর কেন এই "মাঝখানের" ধাপটা সিক্রেট সুরক্ষিত রাখে।

🔒 চিহ্নিত ধাপগুলোই সেই জায়গা যেখানে সিক্রেট ব্যবহার হয় — লক্ষ্য করো এটা কখনো ফ্রন্টএন্ড পর্যন্ত পৌঁছায় না।

ভালো অভ্যাস

  • যেখানে ফ্রন্টএন্ড SDK + Rules যথেষ্ট, সেখানে Worker দরকার নেই — অপ্রয়োজনীয় জটিলতা বাড়ানো এড়িয়ে চলুন
  • Database Secret সবসময় wrangler secret put দিয়ে যোগ করুন, কখনো কোডে বা wrangler.toml-এ লিখবেন না
  • CORS-এ নির্দিষ্ট origin রাখুন — এই Worker-ই যেহেতু সিক্রেট অ্যাক্সেস দিচ্ছে, সবার জন্য খোলা রাখা আরও ঝুঁকিপূর্ণ

নিজে চেষ্টা করো

Exercise:

  1. নিজের RTDB-এর একটা পাবলিক-read নোড থেকে সাধারণ fetch() দিয়ে Worker-এ ডেটা আনো (সিক্রেট ছাড়াই)।
  2. Firebase Console থেকে একটা Database Secret জেনারেট করো, wrangler secret put দিয়ে Worker-এ যোগ করো।
  3. সেই সিক্রেট দিয়ে এমন একটা নোডে লেখো যেখানে Security Rules-এ পাবলিক write বন্ধ — যাচাই করো Worker দিয়ে ঠিকই লেখা যাচ্ছে।
  4. উপরের প্রক্সি প্যাটার্ন নিজের একটা Pages প্রজেক্ট থেকে কল করে দেখো, CORS ঠিকমতো কাজ করছে কিনা।

পরের পর্বে যা থাকছে

পরের পর্বে আমরা ঢুকব Cloudflare-এর নিজস্ব স্টোরেজ সার্ভিসে — R2 পরিচিতি, যা ফাইল ও ইমেজ স্টোরেজের জন্য Firebase Storage-এর একটা শক্তিশালী বিকল্প, বিশেষ করে egress ফি না থাকার কারণে।

একটি মন্তব্য পোস্ট করুন

নবীনতর পূর্বতন

যোগাযোগ ফর্ম