介紹
PostgRest 是一款直接無痛把 Postgresql db 直接轉成 可以用來當作 api 服務的 工具
不用在特別在另外開一個 Api Service
從 controller , service 一路刻到 repository 最後才能拿到資料
然後才要設想如何 回傳資料給 前端
對需要快速 POC 或是 驗證心中想法
的事項 都能提升 一大段時間
安裝
我就直接使用 docker 安裝 postgresql + postgrest
讓這兩者在同一 docker-compose.yml 網路下 也就可以不用解那些奇奇怪怪的網路問題
version: '3'
services:
postgres:
image: postgres:18
restart: always
environment:
POSTGRES_USER: {{YOUR_DB_USER_NAME}}
POSTGRES_PASSWORD: {{YOUT_DB_PASSWORD}}
POSTGRES_DB: postgres
POSTGRES_MAX_CONNECTIONS: 100
ports:
- "5432:5432"
volumes:
- ./data:/var/lib/postgresql
pgbouncer:
image: edoburu/pgbouncer:1.22.1
restart: always
depends_on:
- postgres
ports:
- "6432:6432"
environment:
POOL_MODE: transaction
MAX_CLIENT_CONN: 2000
DEFAULT_POOL_SIZE: 40
MIN_POOL_SIZE: 10
RESERVE_POOL_SIZE: 10
SERVER_RESET_QUERY: DISCARD ALL
IGNORE_STARTUP_PARAMETERS: extra_float_digits
volumes:
- ./pgbouncer:/etc/pgbouncer
postgrest:
image: postgrest/postgrest:latest
container_name: postgrest
environment:
- PGRST_DB_URI=postgres://{{YOUR_DB_USER_NAME}}:{{YOUT_DB_PASSWORD}}@pgbouncer:6432/postgres
- PGRST_DB_SCHEMA=public
- PGRST_DB_ANON_ROLE=anon
ports:
- "3000:3000"
depends_on:
- postgres
將以上 docker-compose.yml 放在一個好地方
補充 pgbouncer 需要再相對位置 增加兩個file
需要開一個資料夾
mkdir ./pgbouncer
cd pgbouncer
新增以下檔案
- pgbouncer.ini
[databases]
postgres = host=postgres port=5432 dbname=postgres
[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 2000
default_pool_size = 40
min_pool_size = 10
reserve_pool_size = 10
server_reset_query = DISCARD ALL
ignore_startup_parameters = extra_float_digits
admin_users = {{your_db_user}}
log_connections = 1
log_disconnections = 1
- userlist.txt
"your_db_account" "your_db_password"
密碼可以使用md5 但我沒有試成功 要怎麼做 以後再來看
然後執行
docker-compose up -d
就可以將服務執行在背景了
此次範例的 sql ddl 為
table name = flower_prod_day_trans
CREATE TABLE public.flower_prod_day_trans (
trans_date date NOT NULL,
trans_date_roc text NULL,
query_time timestamp NULL,
query_time_roc text NULL,
market text NOT NULL,
product text NOT NULL,
max_price numeric NULL,
high_price numeric NULL,
mid_price numeric NULL,
low_price numeric NULL,
avg_price numeric NULL,
price_change_pct numeric NULL,
volume int4 NULL,
volume_change_pct numeric NULL,
residual_volume int4 NULL,
result_title text NULL,
source_url text NULL,
raw jsonb NULL,
inserted_at timestamptz DEFAULT now() NOT NULL,
updated_at timestamptz DEFAULT now() NOT NULL,
CONSTRAINT flower_prod_day_trans_pkey PRIMARY KEY (trans_date, market, product)
);
配置 Postgrest 的匿名使用者
進入到 docker postgres db
docker exec -it postresql-docker_postgres_1 psql -U {{YOUR_USER_NAME}} -d postgres
然後輸入以下
CREATE ROLE anon nologin;
GRANT anon TO postgres;
GRANT SELECT ON schema public TO anon;
GRANT SELECT ON public.flower_prod_day_trans TO anon;
可以嘗試呼叫
curl http://127.0.0.1:3000
就可以看到 swagger 的doc了
curl http://127.0.0.1:3000/flower_prod_day_trans?limit=1
就可以取到一筆資料了
新增表
現在如果我有一張新的表 叫做 cache 要加入 anon 的可select 權限
則需要再進入到 postgresql docker 中
docker exec -it postresql-docker_postgres_1 psql -U {{YOUR_USER_NAME}} -d postgres
接著輸入
GRANT SELECT ON public.cache TO anon;
再到cmd 測試
curl http://127.0.0.1:3000/cache
就可以查到資料了
當你需要 group by 的話
會出現以下錯誤
{"code":"PGRST123","details":null,"hint":null,"message":"Use of aggregate functions is not allowed"}
因為預設 是不支持 group by 的
因為這樣有可能 讓使用者 可以自己 group by 他可以group幾百萬行 容易打爆資料庫
但如果真的需要使用的話
需要於 docker-compose 中增加
PGRST_DB_AGGREGATES_ENABLED=true
就可以使用
http://xxxxxx/yout_table?select=volume.sum(),name
- count()
http://xxxxxx/yout_table?select=volume.count(),name
但就會有另外的問題 如果要group by sum()然後 order by sum() 呢
http://xxxxxx/yout_table?select=volume.sum(),trans_date&order=volume.sum().asc ?
很抱歉 目前不支持
如果真的要做 寫成一個view 吧
然後記得放對資料表位置 也要確認是否有授權給 驗證的帳號
條件查詢
就直接把欄位打上去就好 比如需要 查詢 “700 台南市場” 就會是
market=eq.700%20台南市場
%20 = 空白號
為 URL encodeing
in
查「700 台南市場」或「800 高雄市場」
market=in.(700 台南市場,800 高雄市場)
market=in.(700%20%E5%8F%B0%E5%8D%97%E5%B8%82%E5%A0%B4,800%20%E9%AB%98%E9%9B%84%E5%B8%82%E5%A0%B4)
like
market 包含「台南」
market=like.%25台南%25
等同於 SQL
market LIKE ‘%台南%‘
%25 = 百分比符號
查日期區間
查 2026-01-18 ~ 2026-01-19
trans_date=gte.2026-01-18&trans_date=lte.2026-01-19
補充 我的欄位型別是
trans_date → date
query_time → timestamp
inserted_at → timestamptz
updated_at → timestamptz
某時間之後
/query_time=gte.2026-01-19T11:00:00
對照表
| 運算子 | 意義 |
|---|---|
| eq | = |
| neq | != |
| gt | > |
| gte | >= |
| lt | < |
| lte | <= |
| like | LIKE |
| ilike | ILIKE |
| in | IN |
| is | IS (null / true / false) |
如果需要做新增?
如果需要做新增資料 需要再想以下事項
- 權限管理 token 相關 (註冊,登入,jwt驗證)
- 資料列層級安全性(Row-Level Security)
- 萬一 寫爆資料庫? (雖然讀也有一樣問題)
有稍微看了看 可以無腦直接 開insert 給 某user 但這樣做會有很大的風險
於是就不探討了
問了 下gemini 有以下回饋
方案 A:使用 Supabase (目前最紅)
Supabase 本質上就是 Postgres + PostgREST + GoTrue (認證模組)。
它不讓你手寫 login function。
它提供一個專門處理登入、註冊、第三方登入的服務(GoTrue)。
登入後,它會發放 JWT,這個 JWT 直接給 PostgREST 用,觸發你寫在資料庫裡的 RLS。
結論: 這是目前「既想用 RLS 威力,又不想手寫 SQL 登入」的最佳實務。
方案 B:自建小型 Auth API
你自己寫一個簡單的 Node.js/Express,只負責 /login 和 /signup。
驗證成功後,用同樣的 JWT_SECRET 簽發 Token 給前端。
剩下的所有資料操作(CRUD)全部直接交給 PostgREST。
就這樣吧 感謝