Flutter for OpenHarmony:postgrest 直接访问 PostgreSQL 数据库的 RESTful 客户端(Supabase 核心驱动) 深度解析与鸿蒙适配指南
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net

前言
如果你不想写复杂的 Java/Node.js 后端服务,只想直接增删改查数据库,PostgREST 是一个神奇的后端工具 —— 它能把从 PostgreSQL 数据库自动生成一套 RESTful API。而 postgrest (Dart库) 正是这一服务的官方客户端。
这也是 Supabase(Firebase 的开源替代品)的核心组件之一。通过它,你可以在 Flutter App 中像写 SQL 一样流畅地操作远程数据,既安全又高效。
一、概念介绍/原理解析
1.1 基础概念
- Filter:
eq('id', 1),gt('age', 18)等,对应 SQL 的WHERE。 - Select: 指定返回字段,支持关联查询(如
*, posts(*))。 - Order: 排序规则。
- RPC: 调用存储过程(Stored Procedures)。
HTTP 请求
SQL 语句
结果集
JSON 数据
Flutter 移动应用
PostgREST 接口网关
后台数据库
1.2 进阶概念
虽然看起来是直连数据库,但实际上通过 PostgREST 的 RLS (Row Level Security) 机制,你可以非常精细地控制每个用户只能读写自己的数据,无需担心越权。
二、核心 API/组件详解
2.1 基础用法
查询数据。
import'package:postgrest/postgrest.dart';final client =PostgrestClient('https://your-project.supabase.co/rest/v1');voidmain()async{// SELECT * FROM countries WHERE name = 'China'final data =await client .from('countries').select().eq('name','China');print(data);// List<Map<String, dynamic>>}
2.2 插入与更新
// INSERT INTO users (name, status) VALUES ('Tom', 'active')await client.from('users').insert({'name':'Tom','status':'active'});// UPDATE users SET status = 'inactive' WHERE id = 1await client.from('users').update({'status':'inactive'}).eq('id',1);
三、常见应用场景
3.1 场景 1:无后端 App
基于 Supabase 或自建 PostgREST,直接开发 CMS 或简单的社交应用。
// 获取文章列表及作者信息final posts =await client.from('posts').select('*, author:users(*)');
3.2 场景 2:实时排行榜
虽然 postgrest 主要是 REST,但结合 Realtime 功能(Supabase),可实现实时数据同步。
// 仅使用 postgrest 获取快照final top10 =await client.from('scores').select().order('score', ascending:false).limit(10);
3.3 场景 3:调用复杂业务逻辑
通过 RPC 调用数据库函数。
// 调用名为 "reset_password" 的函数await client.rpc('reset_password', params:{'email':'[email protected]'});
四、OpenHarmony 平台适配
4.1 网络请求库
postgrest 内部默认使用 http 库。在 OpenHarmony 上,这完全没问题。如果你需要自定义(比如加 Token 拦截器或使用 Dio),可以通过构造函数传入自定义 Client。
4.2 权限声明
同样别忘了在鸿蒙 config.json/module.json5 中声明 ohos.permission.INTERNET。
五、完整示例代码
本示例列出所有任务 (Todos),并支持点击切换完成状态。
import'package:flutter/material.dart';import'package:postgrest/postgrest.dart';// 请替换为你自己的 PostgREST 服务地址constString _url ='https://my-project.supabase.co/rest/v1';constString _anonKey ='your-anon-key';// 如果有的话voidmain(){runApp(constMaterialApp(home:TodoPage()));}classTodoPageextendsStatefulWidget{constTodoPage({super.key});@overrideState<TodoPage>createState()=>_TodoPageState();}class _TodoPageState extendsState<TodoPage>{ late finalPostgrestClient _client;List<Map<String,dynamic>> _todos =[]; bool _loading =true;@overridevoidinitState(){super.initState(); _client =PostgrestClient( _url, headers:{'apikey': _anonKey},// 公钥);_fetchTodos();}Future<void>_fetchTodos()async{try{final res =await _client.from('todos').select().order('id');setState((){ _todos =List<Map<String,dynamic>>.from(res asList); _loading =false;});}catch(e){print('Error: $e');setState(()=> _loading =false);}}Future<void>_toggle(int id, bool current)async{// 乐观更新 UIfinal index = _todos.indexWhere((t)=> t['id']== id);if(index !=-1){setState((){ _todos[index]['is_complete']=!current;});}try{await _client.from('todos').update({'is_complete':!current}).eq('id', id);}catch(e){// 失败回滚..._fetchTodos();}}@overrideWidgetbuild(BuildContext context){returnScaffold( appBar:AppBar(title:constText('PostgREST Todos')), body: _loading ?constCenter(child:CircularProgressIndicator()):ListView.builder( itemCount: _todos.length, itemBuilder:(context, index){final todo = _todos[index];final isDone = todo['is_complete']as bool???false;returnCheckboxListTile( title:Text(todo['task']asString), value: isDone, onChanged:(_)=>_toggle(todo['id']as int, isDone),);},), floatingActionButton:FloatingActionButton( onPressed: _fetchTodos, child:constIcon(Icons.refresh),),);}}
六、总结
postgrest 极大地降低了全栈开发的门槛。前端开发者只需专注于 UI 和数据查询,复杂的后端逻辑交给强大的 PostgreSQL 数据库去处理。
最佳实践:
- 安全性:永远不要在客户端使用
service_role密钥(超级管理员权限)。始终使用anon密钥配合 RLS。 - 类型生成:手动解析
Map<String, dynamic>很累且容易出错,建议使用supabase_flutter配合代码生成工具。