Hasura详解
Hasura概述
Hasura是一个开源的GraphQL引擎,能够自动将PostgreSQL数据库转换为GraphQL API。它提供了实时数据订阅、细粒度的权限控制、事件触发器等功能,使开发者能够快速构建数据驱动的应用程序。
Hasura成立于2018年,目前已成为GraphQL生态系统中重要的组成部分,被众多公司和组织采用,包括Red Hat、Auth0、IBM等。
Hasura的核心特性
1. 自动生成GraphQL API
Hasura能够自动根据PostgreSQL数据库模式生成完整的GraphQL API,包括查询、变更和订阅操作,无需编写任何后端代码。
2. 实时数据订阅
通过GraphQL订阅,客户端可以实时接收数据库变更通知,适用于构建聊天应用、实时仪表盘等需要实时数据的场景。
3. 细粒度的权限控制
Hasura提供了强大的权限系统,可以基于角色和用户定义细粒度的数据访问控制规则,确保数据安全。
4. 事件触发器
Hasura的事件触发器可以在数据库发生变更时触发Webhook,实现业务逻辑处理、通知等功能。
5. 远程Schema集成
Hasura允许集成远程GraphQL服务,将多个GraphQL API合并为一个统一的API。
6. 数据库视图和自定义函数支持
支持PostgreSQL视图和自定义函数,可以在Hasura中直接使用这些数据库对象。
安装和配置Hasura
1. 使用Docker安装
# 创建docker-compose.yml文件
version: '3.6'
services:
postgres:
image: postgres:13
restart: always
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: postgrespassword
graphql-engine:
image: hasura/graphql-engine:v2.20.0
ports:
- "8080:8080"
depends_on:
- postgres
restart: always
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
HASURA_GRAPHQL_ENABLE_CONSOLE: "true" # 启用控制台
HASURA_GRAPHQL_DEV_MODE: "true" # 开发模式
HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
volumes:
db_data:
启动服务:
docker-compose up -d
访问Hasura控制台:http://localhost:8080,使用admin secret key(myadminsecretkey)登录。
2. 使用Hasura Cloud
Hasura Cloud提供了托管的Hasura服务,无需自己管理基础设施:
- 访问https://cloud.hasura.io注册账号
- 创建新项目
- 连接到现有PostgreSQL数据库或创建新数据库
- 开始使用Hasura控制台
连接数据库
1. 添加PostgreSQL数据库
- 在Hasura控制台中,导航到"Data"标签页
- 点击"Connect Database"按钮
- 选择"PostgreSQL"
- 输入数据库连接信息:
- 数据库URL:postgresql://username:password@hostname:port/database
- 数据库名称(可选)
- 点击"Connect Database"按钮
2. 跟踪现有表和视图
连接数据库后,Hasura会显示所有可用的表和视图:
- 选择要跟踪的表或视图
- 点击"Track"按钮
- Hasura会自动生成相关的GraphQL查询和变更
3. 创建新表
也可以在Hasura控制台中直接创建新表:
- 导航到"Data"标签页
- 点击"Create Table"按钮
- 定义表结构(表名、字段、类型、约束等)
- 点击"Add Table"按钮
GraphQL查询操作
1. 基本查询
Hasura自动为每个表生成查询操作:
query GetUsers {
users {
id
name
email
created_at
}
}
2. 过滤和排序
query GetFilteredUsers {
users(where: { age: { _gt: 18 } }, order_by: { created_at: desc }) {
id
name
age
}
}
3. 分页查询
query GetUsersWithPagination {
users(
limit: 10
offset: 20
order_by: { created_at: desc }
) {
id
name
email
}
users_aggregate {
aggregate {
count
}
}
}
4. 关系查询
Hasura会自动检测和利用数据库中的外键关系:
query GetUserWithPosts {
users_by_pk(id: 1) {
id
name
email
posts {
id
title
content
created_at
}
}
}
GraphQL变更操作
1. 插入数据
mutation InsertUser {
insert_users_one(object: {
name: "张三",
email: "zhangsan@example.com",
age: 25
}) {
id
name
email
}
}
# 批量插入
mutation InsertMultipleUsers {
insert_users(objects: [
{ name: "李四", email: "lisi@example.com" },
{ name: "王五", email: "wangwu@example.com" }
]) {
returning {
id
name
}
}
}
2. 更新数据
mutation UpdateUser {
update_users_by_pk(pk_columns: { id: 1 }, _set: {
name: "张三更新",
age: 26
}) {
id
name
age
}
}
# 条件更新
mutation UpdateMultipleUsers {
update_users(where: { age: { _lt: 18 } }, _set: {
status: "未成年"
}) {
affected_rows
returning {
id
name
status
}
}
}
3. 删除数据
mutation DeleteUser {
delete_users_by_pk(id: 1) {
id
name
}
}
# 条件删除
mutation DeleteMultipleUsers {
delete_users(where: { status: { _eq: "inactive" } }) {
affected_rows
}
}
实时数据订阅
1. 基本订阅
subscription GetRealTimeUsers {
users {
id
name
email
}
}
2. 带过滤条件的订阅
subscription GetRealTimeNewUsers {
users(order_by: { created_at: desc }, limit: 10) {
id
name
email
created_at
}
}
3. 关系数据订阅
subscription GetUserWithPostsRealtime {
users_by_pk(id: 1) {
id
name
posts {
id
title
content
}
}
}
权限控制
1. 创建用户角色
- 在Hasura控制台中,导航到"Settings" > "Roles"标签页
- 点击"Create New Role"按钮
- 输入角色名称(如:user、admin等)
- 点击"Save"按钮
2. 定义表级权限
- 导航到"Data"标签页,选择要设置权限的表
- 点击"Permissions"标签页
- 选择角色,然后设置以下权限:
- Select: 设置查询权限
- Insert: 设置插入权限
- Update: 设置更新权限
- Delete: 设置删除权限
- 为每个权限定义过滤条件和列选择限制
- 点击"Save Permissions"按钮
3. 权限规则示例
用户只能访问自己的数据
{
"id": {"_eq": "X-Hasura-User-Id"}
}
基于用户角色的权限
{
"role": {"_eq": "X-Hasura-Role"}
}
组合条件
{
"_and": [
{"status": {"_eq": "active"}},
{"visibility": {"_eq": "public"}}
]
}
4. 会话变量
Hasura使用会话变量来实现基于用户的权限控制,常用的会话变量包括:
X-Hasura-User-Id: 用户IDX-Hasura-Role: 用户角色- 自定义会话变量
这些变量可以通过认证服务或JWT令牌传递给Hasura。
事件触发器
1. 创建事件触发器
- 在Hasura控制台中,导航到"Events"标签页
- 点击"Create Event Trigger"按钮
- 配置触发器:
- 名称:触发器的唯一标识符
- 模式:选择数据库模式
- 表:选择要监听的表
- 操作:选择要监听的操作(INSERT、UPDATE、DELETE)
- Webhook URL:事件触发时调用的HTTP端点
- 点击"Create"按钮
2. 事件有效载荷示例
当事件被触发时,Hasura会向配置的Webhook URL发送HTTP POST请求,请求体包含事件详情:
{
"event": {
"op": "INSERT",
"data": {
"old": null,
"new": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"created_at": "2023-04-01T10:00:00Z"
}
}
},
"table": {
"name": "users",
"schema": "public"
},
"trigger": {
"name": "user_created"
},
"created_at": "2023-04-01T10:00:01.234Z",
"delivery_info": {
"max_retries": 0,
"current_retry": 0
}
}
3. 重试策略
Hasura支持为事件触发器配置重试策略:
- 最大重试次数
- 重试间隔
- 指数退避
4. 事件队列管理
在"Events"标签页中,可以查看和管理事件队列:
- 查看待处理事件
- 重新触发失败的事件
- 监控事件处理状态
远程Schema集成
1. 添加远程Schema
- 在Hasura控制台中,导航到"Remote Schemas"标签页
- 点击"Add Remote Schema"按钮
- 配置远程Schema:
- 名称:远程Schema的唯一标识符
- GraphQL服务器URL:远程GraphQL服务的端点
- 可选的头部信息(认证令牌等)
- 点击"Add Remote Schema"按钮
2. 权限传播
可以为远程Schema配置权限传播,将Hasura的会话变量传递给远程服务:
- 编辑远程Schema配置
- 在"Headers"部分,添加自定义头部
- 使用会话变量作为头部值:
{{$x-hasura-user-id}}
3. 示例:集成认证服务
# 远程认证服务的Schema
type AuthPayload {
token: String!
user: User!
}
type Mutation {
login(email: String!, password: String!): AuthPayload!
register(email: String!, password: String!): AuthPayload!
}
集成后,可以在Hasura中直接调用这些突变操作:
mutation Login {
login(email: "user@example.com", password: "password") {
token
user {
id
name
}
}
}
自定义SQL函数
1. 创建自定义函数
可以在PostgreSQL中创建自定义函数,然后在Hasura中使用:
CREATE OR REPLACE FUNCTION public.get_user_post_count(user_id integer)
RETURNS integer AS $$
SELECT COUNT(*) FROM public.posts WHERE posts.user_id = user_id;
$$ LANGUAGE sql STABLE;
2. 在Hasura中跟踪函数
- 在Hasura控制台中,导航到"Data"标签页
- 选择"SQL Functions"选项卡
- 找到创建的函数(get_user_post_count)
- 点击"Track"按钮
3. 在GraphQL查询中使用函数
query GetUserWithPostCount {
users {
id
name
post_count: get_user_post_count(user_id: id)
}
}
视图和物化视图
1. 创建视图
CREATE VIEW public.user_with_post_count AS
SELECT
u.id,
u.name,
u.email,
COUNT(p.id) AS post_count
FROM public.users u
LEFT JOIN public.posts p ON u.id = p.user_id
GROUP BY u.id;
2. 在Hasura中跟踪视图
- 在Hasura控制台中,导航到"Data"标签页
- 选择"Views"选项卡
- 找到创建的视图(user_with_post_count)
- 点击"Track"按钮
3. 在GraphQL查询中使用视图
query GetUsersWithPostCount {
user_with_post_count {
id
name
email
post_count
}
}
性能优化
1. 索引优化
为常用查询字段添加索引可以显著提高查询性能:
-- 为users表的email字段添加唯一索引
CREATE UNIQUE INDEX idx_users_email ON public.users(email);
-- 为posts表的user_id和created_at字段添加复合索引
CREATE INDEX idx_posts_user_id_created_at ON public.posts(user_id, created_at DESC);
2. 查询优化
- 使用
_agg查询获取聚合数据 - 避免在大型数据集上使用无限制的查询
- 使用分页查询限制返回的数据量
- 只请求需要的字段,避免过度获取
3. 订阅优化
- 使用过滤条件减少订阅的数据量
- 对于频繁更新的数据,考虑使用轮询或批处理更新
- 监控订阅性能,及时调整策略
4. 数据库优化
- 定期维护PostgreSQL数据库
- 调整PostgreSQL配置参数(shared_buffers、work_mem等)
- 考虑使用连接池提高并发性能
认证集成
1. JWT认证
Hasura支持使用JWT令牌进行认证:
-
配置JWT密钥:
HASURA_GRAPHQL_JWT_SECRET='{"type":"HS256","key":"your-secret-key"}' -
JWT令牌示例:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"https://hasura.io/jwt/claims": {
"x-hasura-user-id": "1",
"x-hasura-role": "user",
"x-hasura-default-role": "user"
}
}
2. Webhook认证
也可以使用自定义Webhook进行认证:
HASURA_GRAPHQL_AUTH_HOOK=http://your-auth-service.com/auth
Webhook需要返回包含Hasura会话变量的JSON响应:
{
"X-Hasura-User-Id": "1",
"X-Hasura-Role": "user",
"X-Hasura-Is-Owner": "true"
}
部署最佳实践
1. 生产环境配置
- 禁用开发模式和未认证访问
- 使用强管理员密钥
- 配置适当的资源限制
- 启用SSL/TLS加密
# 生产环境环境变量
HASURA_GRAPHQL_ENABLE_CONSOLE=false
HASURA_GRAPHQL_DEV_MODE=false
HASURA_GRAPHQL_ADMIN_SECRET=strong-admin-secret
HASURA_GRAPHQL_JWT_SECRET='{"type":"RS256","jwk_url":"https://your-auth-service.com/.well-known/jwks.json"}'
2. 数据库最佳实践
- 使用专用的PostgreSQL用户和数据库
- 配置适当的数据库连接池大小
- 定期备份数据库
- 监控数据库性能
3. 高可用性部署
- 使用多个Hasura实例
- 配置负载均衡
- 实现自动扩展
- 考虑多区域部署
监控和日志
1. 日志配置
Hasura支持多种日志类型:
HASURA_GRAPHQL_ENABLED_LOG_TYPES=startup, http-log, webhook-log, websocket-log, query-log
2. 查询分析
在Hasura控制台中,可以查看和分析查询性能:
- 导航到"Settings" > "Logs"标签页
- 查看执行的查询和性能指标
- 识别慢查询并进行优化
3. 集成监控系统
Hasura可以集成各种监控系统:
- Prometheus和Grafana
- Datadog
- New Relic
Hasura的优缺点
优点
- 开发速度快:自动生成GraphQL API,无需编写后端代码
- 实时功能强大:内置GraphQL订阅支持
- 权限系统灵活:细粒度的访问控制
- 易于集成:可以与现有系统和服务集成
- 开源免费:核心功能开源免费
缺点
- 数据库限制:主要支持PostgreSQL,对其他数据库支持有限
- 复杂业务逻辑:复杂的业务逻辑仍需编写自定义服务
- 学习曲线:对于GraphQL新手有一定的学习曲线
- 自定义功能:某些自定义功能可能需要额外工作
总结
Hasura是一个强大的GraphQL引擎,能够显著加速数据驱动应用的开发。它通过自动生成GraphQL API、提供实时数据订阅、强大的权限控制和事件触发器等功能,使开发者能够专注于业务逻辑的实现,而不必花费大量时间在基础设施和API开发上。
无论是构建原型还是生产级应用,Hasura都能提供高效、灵活的解决方案。通过与PostgreSQL的深度集成和丰富的扩展功能,Hasura为现代Web和移动应用开发提供了强大的支持。