Bỏ qua

Edge Functions Concepts

Edge Functions là gì?

Overview

┌─────────────────────────────────────────────────────────────┐
│                  SUPABASE EDGE FUNCTIONS                     │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  Client ──▶ Edge Function ──▶ Supabase DB / External APIs  │
│                  │                                          │
│                  │                                          │
│           ┌──────┴──────┐                                   │
│           │    Deno     │                                   │
│           │   Runtime   │                                   │
│           └─────────────┘                                   │
│                                                              │
│  Features:                                                   │
│  - Server-side TypeScript/JavaScript                        │
│  - Deno runtime (secure by default)                        │
│  - Global edge deployment                                   │
│  - Native Supabase integration                             │
│  - External API calls                                       │
│  - Webhooks handling                                        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

When to Use Edge Functions

Use Cases

┌─────────────────────────────────────────────────────────────┐
│                      USE CASES                               │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ✅ GOOD for:                                                │
│  - External API integration (Stripe, SendGrid, etc.)       │
│  - Webhooks from third-party services                      │
│  - Complex business logic                                   │
│  - Data transformation before storage                      │
│  - Custom authentication flows                             │
│  - Scheduled tasks (with cron)                             │
│                                                              │
│  ❌ NOT ideal for:                                           │
│  - Simple CRUD (use REST API directly)                     │
│  - Database-only operations (use RPC/triggers)             │
│  - Long-running tasks (30s timeout)                        │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Project Structure

Local Setup

# Initialize Supabase project
supabase init

# Create new function
supabase functions new my-function

# Project structure
supabase/
├── functions/
   ├── my-function/
      └── index.ts        # Function code
   ├── another-function/
      └── index.ts
   └── _shared/            # Shared utilities
       └── supabase-client.ts
├── config.toml
└── seed.sql

Basic Function Structure

Hello World

// supabase/functions/hello/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";

serve(async (req: Request) => {
  const { name } = await req.json();

  return new Response(
    JSON.stringify({ message: `Hello ${name}!` }),
    {
      headers: { "Content-Type": "application/json" },
    }
  );
});

With Supabase Client

// supabase/functions/get-user/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

serve(async (req: Request) => {
  // Create Supabase client
  const supabase = createClient(
    Deno.env.get("SUPABASE_URL") ?? "",
    Deno.env.get("SUPABASE_ANON_KEY") ?? "",
    {
      global: {
        headers: { Authorization: req.headers.get("Authorization")! },
      },
    }
  );

  // Get user from JWT
  const { data: { user } } = await supabase.auth.getUser();

  return new Response(
    JSON.stringify({ user }),
    { headers: { "Content-Type": "application/json" } }
  );
});

Deno Runtime

Key Differences from Node.js

// Deno uses URL imports
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

// Environment variables
const apiKey = Deno.env.get("API_KEY");

// Fetch is built-in (no node-fetch needed)
const response = await fetch("https://api.example.com");

// Top-level await is supported
const data = await response.json();

Import Map (Optional)

// supabase/functions/import_map.json
{
  "imports": {
    "@supabase/supabase-js": "https://esm.sh/@supabase/supabase-js@2",
    "std/": "https://deno.land/std@0.168.0/"
  }
}

CORS Handling

Basic CORS

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers":
    "authorization, x-client-info, apikey, content-type",
};

serve(async (req: Request) => {
  // Handle preflight
  if (req.method === "OPTIONS") {
    return new Response("ok", { headers: corsHeaders });
  }

  // Your function logic
  const data = { message: "Hello" };

  return new Response(JSON.stringify(data), {
    headers: { ...corsHeaders, "Content-Type": "application/json" },
  });
});

Environment Variables

Setting Secrets

# Set secret (production)
supabase secrets set MY_API_KEY=sk_live_xxxxx

# Set multiple
supabase secrets set \
  STRIPE_KEY=sk_live_xxx \
  SENDGRID_KEY=SG.xxx

# List secrets
supabase secrets list

# Local development (.env.local)
# supabase/functions/.env.local
MY_API_KEY=sk_test_xxxxx

Accessing in Function

const apiKey = Deno.env.get("MY_API_KEY");

// Built-in Supabase variables (auto-available)
const supabaseUrl = Deno.env.get("SUPABASE_URL");
const supabaseAnonKey = Deno.env.get("SUPABASE_ANON_KEY");
const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY");

Invoking Functions

From Client

// Using supabase-js
const { data, error } = await supabase.functions.invoke("my-function", {
  body: { name: "World" },
});

// With custom headers
const { data, error } = await supabase.functions.invoke("my-function", {
  body: { name: "World" },
  headers: { "Custom-Header": "value" },
});

Direct HTTP

# Using curl
curl -X POST \
  'https://project-ref.supabase.co/functions/v1/my-function' \
  -H 'Authorization: Bearer ANON_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"name": "World"}'

Local Development

Serve Locally

# Serve all functions
supabase functions serve

# Serve specific function
supabase functions serve my-function

# With env file
supabase functions serve --env-file ./supabase/.env.local

# Debug mode
supabase functions serve --debug

Test Locally

# Invoke local function
curl -X POST \
  'http://localhost:54321/functions/v1/my-function' \
  -H 'Authorization: Bearer ANON_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"name": "Test"}'

Tổng kết

Edge Functions Basics

Aspect Detail
Runtime Deno (TypeScript/JavaScript)
Timeout 30 seconds
Memory 150MB
Deployment Global edge network
Auth JWT from Authorization header

Key Commands

supabase functions new <name>   # Create function
supabase functions serve        # Local dev
supabase functions deploy       # Deploy
supabase secrets set KEY=value  # Set secrets

Q&A

  1. Có use case nào cần Edge Functions?
  2. Đã làm việc với Deno chưa?
  3. Cần integrate external APIs nào?