# Supabase SDK使用
#### 操作场景
本章节提供基于前端脚手架和基于不同API Key的Supabase SDK使用方法。
#### 基于前端脚手架的Supabase SDK使用
#### 前提条件
- 已创建Supabase AI应用，且应用运行状态正常。
- 如需公网访问应用，请参考[绑定和解绑DNAT网关地址](https://support.huaweicloud.com/usermanual-rds-pg/rds_supabase_15.html)绑定公网EIP。
- 确保您项目所选框架的依赖和软件均已安装，并正确配置。 例如，已选择前端React框架，请安装[Node.js](https://nodejs.org)，并确保npm可用。
  
 
#### 步骤1：获取Supabase环境变量（访问地址与API Key）
1. [登录RDS管理控制台](https://console.huaweicloud.com/rds/#/rds/management/list)。
2. 单击管理控制台左上角的![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002606863935.png)，选择区域。
3. 在左侧导航栏，选择"AI应用开发平台"，在应用列表中找到目标Supabase应用。
4. 单击"操作"列的"登录应用"。
5. 在弹窗中，根据所在网络环境，单击对应方式方式下的"立即登录"，进入Supabase Dashboard界面。
   图1Supabae Dashboard首页   
   ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002720326876.png "点击放大")
   - 登录用户名为supabase。
   
   - 登录密码在应用创建时由用户自定义设置。
    
6. 在页面左上方，单击"Connect"，进入项目连接配置界面。
7. 选择"App Frameworks"，并在Framework下拉框中，根据您项目应用的框架选型，查看对应的.env环境变量配置。
   图2RDS Supabae应用环境变量（以React前端框架为例）   
   ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002749726745.png "点击放大")
   从环境变量配置中获取对应的应用访问地址和Anon API Key。详见[表1]。
    表1环境变量配置项 
   | 配置项              | 对应环境变量                   | 取值示例                 |
   |:---|:---|:---|
   | Supabase应用访问地址 | VITE_SUPABASE_URL          | http://10.x.x.x:8443 |
   | Supabase API Key | VITE_SUPABASE_ANON_KEY | \*\*\*\*\*\*\*\*\*\*  |
      
   
 
#### 步骤2：框架对接SDK（快速启动）
以React前端框架为例，在本地创建脚手架项目，并进行启动，体验完整的无后端开发实践。
1. 参考[Supabase SDK框架官网](https://supabase.com/docs)，根据您项目的技术选型，单击图标进入对应的框架对接指导，充分了解端到端的操作流程和编码实践。
   该页面提供了简单的脚手架演示项目，供您快速上手，体验完整的对接、使用以及启动步骤。
   图3Supabase 框架SDK对接快捷入口   
   ![](https://support.huaweicloud.com/usermanual-rds-pg/zh-cn_image_0000002720167004.png "点击放大") 
2. 根据指导教程提供的模板，快速创建您的应用APP的初始化项目。
   执行如下命令，下载脚手架项目。其中{your-app}替换为您的项目名称（包含英文字母、数字、下划线及中划线）。
   ```
   npm create vite@latest {your-app} -- --template react
   ```
   
3. 安装Supabase Client SDK库。
   进行项目代码目录，执行如下命令，安装SDK包。
   ```
   npm install @supabase/supabase-js
   ```
   
4. 修改Supabase环境变量。 创建如下所示的环境变量文件（名称：.env.local）。并用[步骤1：获取Supabase环境变量（访问地址与API Key）]中获取的内容进行替换。
   ```
   VITE_SUPABASE_URL={Supabase应用访问地址}
   VITE_SUPABASE_PUBLISHABLE_KEY={Supabase API Key}
   ```
   
5. 项目代码对接SDK，并使用相关工具及方法。
   项目中src/lib/supabaseClient.js，对应创建Supabase Client的代码片段，如下所示。
   ```
   import { createClient } from '@supabase/supabase-js'
   const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
   const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
   export const supabase = createClient(supabaseUrl, supabasePublishableKey)
   ```
   创建Supabase Client后，您可以用该Client去调用SDK工具套件和所有方法，如查询数据库数据。
   示例：查询表名为instruments的所有行记录数据。
   ```
   const { data, error } = await supabase.from('instruments').select()
   ```
   
6. 按官网脚手架中配置章节，在Supabase Dashboard中SQL Editor视图创建相关库表数据，并完成其他配置操作。
7. 按官网脚手架中编码章节，补充项目代码内容，完成前端编码工作。
8. 启动项目后，用浏览器打开"http://*localhost* :5173"地址，即可查看instruments表的所有记录数据。
   ```
   npm run dev
   ```
   
 
#### 基于不同API Key的Supabase SDK使用
介绍基于API Key的客户端JavaScript SDK调用示例、服务端JavaScript SDK调用示例、以及Rest API原生JavaScript调用示例。
#### 前提条件
- 已创建Supabase AI应用，并根据所处网络环境，按需开启了公网访问，绑定了EIP和访问端口。
- 已获取应用的API Key，包括：Publishable Key、Secret Key、Anon Key、Service Role Key。
- 已了解[Supabase API调用方式和API清单列表](https://supabase.com/docs/reference)。
- 在客户端配置.env文件，将API Key以及用户信息提供在环境变量中。此处示例仅展示最小示例，生产环境请勿直接使用明文存储密码。 示例：
  ```
  SUPABASE_URL=http://xx:xx:xx:xx:8443
  # 新版API Key
  SUPABASE_PUBLISHABLE_KEY=sb_publishable_xxxx_xx
  SUPABASE_SECRET_KEY=sb_secret_xxxx_xx
  # 旧版API Key（可选）
  ANON_KEY=**********
  SERVICE_ROLE_KEY=**********
  # 用户信息
  TEST_USER_EMAIL=xxxxx
  TEST_USER_PASSWORD=xxxxx
  ```
  创建示例中所需的表，并对其正确赋权。
  ```
  -- ============================================================
  -- 1. 建表
  -- ============================================================
  -- 商品表
  CREATE TABLE products (
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name TEXT NOT NULL,
    category TEXT,
    description TEXT,
    created_at TIMESTAMPTZ DEFAULT now(),
    updated_at TIMESTAMPTZ DEFAULT now()
  );
  -- 商品定价表
  CREATE TABLE product_pricings (
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
    tier TEXT NOT NULL,
    price NUMERIC(10,2) NOT NULL,
    unit TEXT DEFAULT '元/月',
    effective_from DATE DEFAULT current_date,
    created_at TIMESTAMPTZ DEFAULT now()
  );
  -- ============================================================
  -- 2. 启用RLS（Realtime postgres_changes依赖RLS判断可见性）
  -- ============================================================
  ALTER TABLE products ENABLE ROW LEVEL SECURITY;
  ALTER TABLE product_pricings ENABLE ROW LEVEL SECURITY;
  -- ============================================================
  -- 3. RLS策略
  -- ============================================================
  -- anon只读（生产环境推荐）
  CREATE POLICY "anon_select_products"          ON public.products FOR SELECT TO anon USING (true);
  CREATE POLICY "anon_select_product_pricings"  ON public.product_pricings FOR SELECT TO anon USING (true);
  -- anon 全量 CRUD（开发/测试用，取消注释启用）
  -- CREATE POLICY "anon_insert_products"          ON public.products FOR INSERT TO anon WITH CHECK (true);
  -- CREATE POLICY "anon_insert_product_pricings"  ON public.product_pricings FOR INSERT TO anon WITH CHECK (true);
  -- CREATE POLICY "anon_update_products"          ON public.products FOR UPDATE TO anon USING (true) WITH CHECK (true);
  -- CREATE POLICY "anon_update_product_pricings"  ON public.product_pricings FOR UPDATE TO anon USING (true) WITH CHECK (true);
  -- CREATE POLICY "anon_delete_products"          ON public.products FOR DELETE TO anon USING (true);
  -- CREATE POLICY "anon_delete_product_pricings"  ON public.product_pricings FOR DELETE TO anon USING (true);
  -- authenticated 可增删改
  CREATE POLICY "authenticated_select_products"         ON public.products FOR SELECT TO authenticated USING (true);
  CREATE POLICY "authenticated_select_product_pricings" ON public.product_pricings FOR SELECT TO authenticated USING (true);
  CREATE POLICY "authenticated_insert_products"         ON public.products FOR INSERT TO authenticated WITH CHECK (true);
  CREATE POLICY "authenticated_insert_product_pricings" ON public.product_pricings FOR INSERT TO authenticated WITH CHECK (true);
  CREATE POLICY "authenticated_update_products"         ON public.products FOR UPDATE TO authenticated USING (true) WITH CHECK (true);
  CREATE POLICY "authenticated_update_product_pricings" ON public.product_pricings FOR UPDATE TO authenticated USING (true) WITH CHECK (true);
  CREATE POLICY "authenticated_delete_products"         ON public.products FOR DELETE TO authenticated USING (true);
  CREATE POLICY "authenticated_delete_product_pricings" ON public.product_pricings FOR DELETE TO authenticated USING (true);
  -- service_role无需策略，默认绕过RLS
  -- ============================================================
  -- 4. 表级权限（RLS是行级过滤，GRANT是表级门控，两者缺一不可）
  -- ============================================================
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.products TO anon;
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.product_pricings TO anon;
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.products TO authenticated;
  GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.product_pricings TO authenticated;
  GRANT ALL ON TABLE product_pricings TO service_role;
  GRANT ALL ON ALL TABLES IN SCHEMA public TO service_role;
  -- ============================================================
  -- 5. Realtime：将表加入已有publication
  -- ============================================================
  ALTER PUBLICATION supabase_realtime ADD TABLE public.products;
  ALTER PUBLICATION supabase_realtime ADD TABLE public.product_pricings;
  -- ============================================================
  -- 6. 示例数据
  -- ============================================================
  INSERT INTO products (name, category, description) VALUES
    ('云存储服务', '软件服务', '企业级对象存储服务，安全可靠'),
    ('GPU 云主机', '硬件', '高性能 GPU 计算实例，适用于 AI 训练与推理'),
    ('API 网关', '软件服务', '统一 API 入口管理，支持限流、鉴权、监控');
  INSERT INTO product_pricings (product_id, tier, price, unit) VALUES
    (1, '基础版', 99.00, '元/月'),
    (1, '专业版', 299.00, '元/月'),
    (1, '企业版', 899.00, '元/月'),
    (2, '标准型', 1280.00, '元/月'),
    (2, '增强型', 3580.00, '元/月'),
    (2, '旗舰型', 8990.00, '元/月'),
    (3, '入门版', 49.00, '元/月'),
    (3, '专业版', 199.00, '元/月');
  -- 刷新PostgREST schema缓存
  NOTIFY pgrst, 'reload schema';
  ```
  
 
#### 基于API Key的客户端JavaScript SDK调用示例（Publishable Key）
- 场景一：不需要登录认证。
  ```
  import "dotenv/config";
  import { createClient } from "@supabase/supabase-js";
  // 创建客户端
  const supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.SUPABASE_PUBLISHABLE_KEY
  );
  // 直接查询，无需登录
  const { data, error } = await supabase
    .from("product_pricings")
    .select("*")
    .limit(10);
  ```
  所访问表需要对"anon"角色放开RLS策略，否则无法查询到数据。
  
- 场景二：需要登录认证。
  ```
  import "dotenv/config";
  import { createClient } from "@supabase/supabase-js";
  // 创建客户端
  const supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.SUPABASE_PUBLISHABLE_KEY
  );
  // 登录
  const { data: loginData, error: loginError } = await supabase.auth.signInWithPassword({
    email: process.env.TEST_USER_EMAIL,
    password: process.env.TEST_USER_PASSWORD,
  });
  // 登录后查询，使用authenticated角色的RLS
  const { data, error } = await supabase
    .from("product_pricings")
    .select("*")
    .limit(10);
  ```
  
 
#### 基于API Key的客户端JavaScript SDK调用示例（Anon Key）
- 场景一：不需要登录认证。
  ```
  import "dotenv/config";
  import { createClient } from "@supabase/supabase-js";
  // 创建客户端
  const supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.ANON_KEY
  );
  // 直接查询，无需登录
  const { data, error } = await supabase
    .from("product_pricings")
    .select("*")
    .limit(10);
  ```
  所访问表需要对"anon"角色放开RLS策略，否则无法查询到数据。
  
- 场景二：需要登录认证。
  ```
  import "dotenv/config";
  import { createClient } from "@supabase/supabase-js";
  // 创建客户端
  const supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.ANON_KEY
  );
  // 登录
  const { data: loginData, error: loginError } = await supabase.auth.signInWithPassword({
    email: process.env.TEST_USER_EMAIL,
    password: process.env.TEST_USER_PASSWORD,
  });
  // 登录后查询，使用authenticated角色的RLS
  const { data, error } = await supabase
    .from("product_pricings")
    .select("*")
    .limit(10);
  ```
  
 
#### 基于API Key的服务端JavaScript SDK调用示例（Secret Key或Service Role Key）
- 场景一：服务端使用Secret Key。
  ```
  import "dotenv/config";
  import { createClient } from "@supabase/supabase-js";
  // 创建客户端
  const supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.SUPABASE_SECRET_KEY
  );
  // 绕过所有RLS，拥有完全数据库权限，无需登录
  const { data, error } = await supabase
    .from("product_pricings")
    .select("*");
  ```
  
- 场景二：服务端使用Service Role Key。
  ```
  import "dotenv/config";
  import { createClient } from "@supabase/supabase-js";
  // 创建客户端
  const supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.SERVICE_ROLE_KEY
  );
  // 绕过所有RLS，拥有完全数据库权限，无需登录
  const { data, error } = await supabase
    .from("product_pricings")
    .select("*");
  ```
  
**Secret Key或Service Role Key不能暴露到前端，仅限服务端开发人员或管理人员使用。**
#### 基于API Key的Rest API原生JavaScript调用示例（Publishable Key）
- 场景一：不需要登录认证。
  ```
  curl -X GET "https://http://xx:xx:xx:xx:8443/rest/v1/product_pricings?select=*" \
  -H "apikey: sb_publishable_xxxx_xx" \
  -H "Authorization: Bearer sb_publishable_xxxx_xx"
  ```
  
- 场景二：需要登录认证。 用户登录（获取JWT）：
  ```
  curl -X POST "https://http://xx:xx:xx:xx:8443/auth/v1/token?grant_type=password" \
  -H "apikey: sb_publishable_xxxx_xx" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "password": "your-password"}'
  ```
  使用用户JWT进行数据请求：
  ```
  curl -X GET "https://http://xx:xx:xx:xx:8443/rest/v1/product_pricings?select=*" \
  -H "apikey: sb_publishable_xxxx_xx" \
  -H "Authorization: Bearer <用户登录后获得的JWT>"
  ```
  
 
#### 基于API Key的Rest API原生JavaScript调用示例（Anon Key）
- 场景一：不需要登录认证。
  ```
  curl -X GET "https://http://xx:xx:xx:xx:8443/rest/v1/product_pricings?select=*" \
  -H "apikey: **********" \
  -H "Authorization: Bearer **********"
  ```
  
- 场景二：需要登录认证。 用户登录（获取JWT）：
  ```
  curl -X POST "https://http://xx:xx:xx:xx:8443/auth/v1/token?grant_type=password" \
  -H "apikey: **********" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "password": "your-password"}'
  ```
  使用用户JWT进行数据请求：
  ```
  curl -X GET "https://http://xx:xx:xx:xx:8443/rest/v1/product_pricings?select=*" \
  -H "apikey: **********" \
  -H "Authorization: Bearer <用户登录后获得的JWT>"
  ```
  
 
