一、前言
当我们开发一个应用程序的时候,通常需要前端和后端各司其职并紧密协作。然而,当一个前端开发者想要独立开发应用时,后端开发的语言和逻辑可能是一片陌生的领域,这就会导致项目充满挑战甚至无法开展,前端必须先了解相关领域的知识才能继续推进。尽管我们能够使用 Node.js 等技术来进行后端开发,但依旧存在额外的复杂性和学习曲线。幸运的是,Supabase 的出现为前端开发者提供了一种全新的全栈开发方式 🎉 Supabase 不仅提供了数据库服务,也是一个全功能的后端服务平台。通过 Supabase,我们不再受限于传统的前后端分离模式,无需编写复杂的后端逻辑,可以直接在前端代码中进行数据库操作。这意味着,即使是没有后端开发背景的前端开发者,也能够独立构建出功能完备的全栈应用,实现从前端到后端的无缝开发体验。本文旨在为读者提供一个全面的 Supabase 使用指南,我们将通过一个简单的项目示例来详细介绍如何使用 Supabase,包括数据库的增删改查、用户认证、文件存储、实时订阅等功能,让我们一起开始探索 Supabase 带来的无限可能吧 🏄 文章分为上下两篇,当前为"上篇"内容:
- 上篇:【基础】介绍 Supabsse 的项目初始化和数据库增删改查操作;
- 下篇:【进阶】介绍 Supabase 的文件上传、用户认证和实时订阅功能;
P.S. Supabase 并不是说让前端来代替后端,在复杂应用场景下后端依旧是不可或缺的核心角色,对于轻量应用而言 Supabase 不失为一种选择,杠就是你对 😊
二、Supabase 是什么?
Supabase 是 Firebase 的开源替代品,是一个后端即服务(BaaS)平台,其允许开发者快速构建和部署应用程序,而无需担心底层基础设施的复杂性。Supabase 当前有六大核心功能(本文主要关注前 4 个核心能力):
- Database:Supabase 使用 PostgreSQL 作为其核心数据库;
- Authentication:Supabase 内置了强大的用户管理系统,支持多种认证方式;
- Storage:Supabase 提供具有无限扩展性的开源对象存储,适用于任何文件类型;
- RealTime:Supabase 支持实时订阅功能,允许开发者订阅各种变化;
- Edge Functions:Supabase 支持轻松创建、部署和监控分布在全球边缘的无服务器函数;
- Vector:Supabase 还提供了向量数据库,为 AI 应用赋能。
Supabase 支持广泛的编程语言,其官方提供了 Javascript/Typescript 和 Flutter 等版本,在社区层面提供了 C#、Go、Java、Python、Ruby、Swift、Kotlin 等各种版本,可在 Github 中找到对应内容,这种多语言支持使得不同背景的开发者都能够轻松地将 Supabase 集成到他们的项目中。在前端框架的兼容性方面,Supabase 同样表现出色。无论你是使用 Next.js、React、Vue、NuxtJS、SvelteKit 还是 SolidJS,Supabase 都能提供无缝的集成体验,这种全面的前端支持确保了开发者可以根据自己的技术栈和偏好选择合适的框架,同时享受到 Supabase 提供的便利。更值得一提的是,Supabase 是一个开源产品,这意味着开发者不仅可以在 Supabase 的官方平台上创建和管理项目,还可以选择在本地进行私有化部署 🎉 这种灵活性为企业提供了一个安全、可控的后端解决方案,同时也让个人开发者能够根据自己的需求定制服务。
三、项目教程
3.1 项目简介
一个简单的商品订单系统,分为三个页面,商品页面、订单页面和登录页面,包含如下功能:
- 用户注册、登陆、登出等功能;
- 商品列表内容的增删改查功能;
- 商品详情支持上传图片文件;
- 订单列表内容的增删查功能;
- 订单列表数据库订阅实时更新;
3.2 初始化
首先,我们需要在 Supabase 中创建一个项目,创建完成后等待项目初始化完成;
然后,根据指引安装依赖后在前端项目中引入,参考 👉 官方文档(不同框架参考 👉 官方文档)
typescript
import { createClient } from "@supabase/supabase-js";
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
const supabase = createClient(supabaseUrl as string, supabaseKey as string);
export default supabase;
3.3 数据库操作
3.3.1 数据表创建
我们需要创建项目所需的数据表,在本项目中我们共需要两张表,分别是产品表 (products)和订单表(orders)。在产品表中包含字段 id、product、productName、productDescription、price 等,在订单表中包含字段 id、productId、productNum、totalPrice 等,其中订单表中的 productId 通过外键与产品表的 id 相关联,实现了两个表的关联。
数据表创建完成后,我们可以尝试直接在平台手动设置字段来插入数据,Supabase 也支持通过 CSV/TSV 文件或解析文本的方式批量导入数据。在项目中我们则会通过接口的方式来插入数据,具体方式详见下节;
3.3.2 增删改查
当我们直接通过接口 API 的方式对表进行查询会发现得到的数据为空;对表进行插入操作会发现接口报错,提示"new row violates row-level security policy for table"。这是由于我们的数据表在创建的时间就选择开启了 RLS 来保护数据安全,我们可以到 Authentication 面板中对表添加 Policies,为了开发方便我们可以先将表的所有操作权限都设置为 public 以对外开放,在完成账户和鉴权功能后中我们可以将其设置为仅有权限的用户才可以进行操作。
3.3.2.1 基础内容
增删改查是数据库最最最基础的操作,Supabase 提供了非常棒的文档系统 👍,当我们创建好数据库表后 Supabase 会基于我们创建的库表定义动态生成我们所需要的 API 文档,我们进入文档可以直接复制相应的代码进行使用,非常清晰易懂!!!
通过这些接口我们前端能够直接对数据库中的数据进行增删改查,前端即使是不懂后端也能轻松实现数据操作 😁 以对商品增删改查为例,代码示例如下:
typescript
// 增
export const createProduct = async (createProduct: CreateProductData) => {
const { data, error } = await supabase.from("products").insert([createProduct]).select().single();
if (error) {
throw new Error(error.message);
}
return data;
};
// 删
export const deleteProduct = async (id: number) => {
const { error } = await supabase.from("products").delete().eq("id", id);
if (error) {
throw new Error(error.message);
}
};
// 改
export const updateProduct = async ({ id, updateProduct }: { id: number; updateProduct: EditProductData }) => {
const { data, error } = await supabase.from("products").update(updateProduct).eq("id", id).select().single();
if (error) {
throw new Error(error.message);
}
return data;
};
// 查
export const getProducts = async () => {
const { data, error } = await supabase.from("products").select("*");
if (error) {
throw new Error(error.message);
}
return data;
};
3.3.2.2 进阶内容
在上面小节中我们介绍了数据库最基础的数据查询的实现,然而在实际应用场景中我们对于数据查询的需求往往更加复杂和多样,例如:
- 查找数据的值需要满足特定条件;
- 查找引用表的内容;
- 对数据按照要求排序;
- 对返回的数据条数进行限制;
- 分页查询数据
- ......
在 Supabase 中查询数据可以与 Filters 和 Modifiers 相结合,更多内容参考 👉 官方文档。在本项目中,支持对商品按价格排序和按照价格范围筛选、对订单关联查找商品的信息等,代码示例如下:
typescript
// 对商品按价格排序 + 对商品按照价格范围筛选
const getProducts = async ({
sortby,
filters,
}: {
sortby?: { field: string; ascending: boolean };
filters?: { field: string; method: string; value: string | number }[];
}) => {
let query = supabase.from("products").select("*");
// 排序
if (sortby) {
query = query.order(sortby.field, { ascending: sortby.ascending });
}
// 过滤
if (filters && filters.length > 0) {
filters.forEach((filter) => {
query = query?.[filter.method]?.(filter.field, filter.value);
});
}
const { data, error } = await query;
if (error) {
throw new Error(error.message);
}
return data;
};
typescript
// 对订单查找关联商品表的信息(商品信息会根据对应的外键查找返回)
const getOrders = async () => {
const { data, error } = await supabase.from("orders").select("*, products(*)");
if (error) {
throw new Error(error.message);
}
return data;
};
四、总结
本文为前端开发者提供了一份详尽的 Supabase 使用指南,本文为上篇,通过一个商品订单系统示例详细演示了从项目初始化到数据库增删改查的全过程,文件存储、用户认证和实时订阅内容请阅读下篇。Supabase 更多更多内容和功能可查阅官方文档进行进一步探索哦 😐 通过 Supabase 提供的能力,前端能够轻松地实现对数据库增删改查、用户权限管理、文件上传、实时订阅等功能,不再需要后端编写相应的接口来提供给前端使用。在某些场景下,Supabase 扩展了前端的能力,前端能够轻松地跳过与数据库之间的后端瓶颈来独立且轻松地实现一个完整的应用。
参考资料: