探索graphQL-hasura引擎
目录
初识Hasura和周边
开门见山说重点
个人理解
使用经验
hasura介绍
API接口性能的描述
how work
action业务逻辑
授权
鉴权
docker安装
其他
初识Hasura和周边
| Hasura | graphQL规范的一种实现,作为graphQL服务器。 |
| GraphQL | GraphQL | A query language for your API GraphQL 是一种API规范,是一个基于类型系统来执行查询的服务端运行时。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。 个人理解:图查询语言 用于检索数据的api查询语言 类比restful规范,用于定义接口;理解为是一种规范,如sql,结构性查询语言,与具体数据库无关。 类型系统:由自定义的各种数据模型构成,包括对象类型、标量、枚举、列表、接口、输入类型等。 最佳实践:通过单入口提供http服务的完整功能,返回json形式。 |
| postgresql | 对象关系型数据库 docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=chl_postgre -d postgres su postgres createdb mydb |
举例:hasura自动生成的graphQL API
| url | http://host:port/v1/graphql |
| method | post |
| header | Content-Type = application/json; charset=utf-8 |
| body | 查询举例: {"query":"query queryAuthor {chl_t_author {id age desc name}}"} |
| 编辑举例: {"query":"mutation MyMutation {insert_chl_t_mv(objects: {author_id: 1, desc: \"mv描述\", name: \"mv14\"}) {returning {id}}}"} |
| 数据模型-维护 |
|
| 数据模型-外键关系 |
|
| 数据模型-角色访问控制 |
|
| grapqlAPI-查询数据 |
|
| grapqlAPI-编辑数据 |
|
| action业务逻辑01-配置graphql和模型 |
|
| action业务逻辑02-访问的rest接口url |
|
| action业务逻辑03-request参数转换 |
|
| action业务逻辑04-response转换 |
|
| action业务逻辑05-调用暴露的graphql |
|
开门见山说重点
个人理解
- graphQL是可以与restful进行类比的API规范,非常灵活的定义API。
- graphQL是定义操作数据的sql规范,API中包括select内容、where条件、order by排序、分页。因此要求使用者需要对graphql语法有些了解。
- 选型因素,hasura快速生成graphQL API和角色权限控制能力。
- hasura作为graphQL规范实现和graphQL服务器,只负责graphQL和模型的关系,不负责任何业务逻辑。
- hasura,非常适合直接crud数据的API,开发效率的确会很高,不需要写代码,配置数据表即可。但是不适合复杂逻辑的API。
- hasura,API添加业务逻辑,需要通过action调用其他http服务,业务逻辑由该http服务实现。在其他http服务中可调用hasura graphQL api操作数据。
- hasura,授权需要依赖外部的授权服务器,也可以是action调用的其他rest API。
- hasura基于角色的鉴权提供了针对‘表、列、操作(graphQL API)’三个维度的访问控制。
- 适用系统:少数接口具有业务逻辑,配置对应的action,绝大多少接口都是直接读写库。
- 数据库模型,面对多表依赖关系,需要明确定义外键。
使用经验
- hasura负责权限控制、数据读写、graphQL API
- restful api负责业务逻辑,数据操作仍然通过调用hasura graphQL API实现。

- 新增数据
可创建单条,多条数据,如单个商品、多个商品
可以同时创建具有外键关系的多条记录,如商品和类目有外键关系,可创建类目同时创建一个商品,要求外键不赋值
例如:执行效果,新建类目记录,商品外键类目id被赋值
mutation MyMutation {insert_chl_t_category(objects: {img: "https://www.itoumi.com/img/home-text.6c72e2f8.png", name: "跳蚤市场", sort: 10, t_base_infos: {data: {content: "跳蚤市场内容xxxx", first_img: "https://www.itoumi.com/img/home-text.6c72e2f8.png", key_desc: "二手 二手", mobile: "13277777777", price: "1999", small_imgs: "https://www.itoumi.com/img/home-text.6c72e2f8.png,https://www.itoumi.com/img/home-text.6c72e2f8.png", title: "跳蚤市场二手01", user_id: 6, recommend_days: 10, service_fee: "10", province_id: 110000, city_id: 110100, county_id: 110101}}}) {returning {idt_base_infos {id}}}
} hasura介绍
哈苏拉 Instant GraphQL APIs on your data | Built-in Authz & Caching
hasura作为graphql服务器,hasura引擎自动基于连接的数据库生成graphql schema,restful接口,GraphQL接口。从API到读写DB都不需要人为编写代码,需要人为介入的有db table的定义,action内容,api调用。
特点包括支持多种数据库、快速从数据库生成统一的生产环境级别的API、API接口性能高等。
API接口性能的描述
- 查询编译,GraphQL查询在JIT编译器中执行,以创建快速查询,避免N+1问题。(在两个表存在一对一,一对多,多对一,多对多等关联信息时,查询一条数据会衍生N条查询的情况就是N+1问题)
- 授权下沉,授权策略被编译为数据访问查询,避免了多次访问,从而大大提高了生产性能
- json聚合 Hasura通过在上游数据库本身中执行JSON聚合,避免了从底层系统获取数据时的笛卡尔乘积问题
- 扩展性,在没有任何配置的情况下,获得线性的垂直(指增加或减少资源,如cpu、内存)和水平(指实例数量的增减)的可扩展性
- 比较查询的数据深度和数据大小,速度都很快,特别在深度增加、数据增大后,表现更明显,10倍+的速度
how work
- graphQL引擎,可以自动基于连接的数据库生成graphql schema,restful接口,GraphQL接口等。
- graphQL引擎,不作为resolver,而是编译graphQL query为真实的sql query。
- metadata,其中描述暴露的graphQL api和所有配置。
控制台基本操作
- 连接数据库
- 创建一个scheme
- 在shceme下创建table
- track模型
- 配置数据权限
- 使用api
action业务逻辑
- what
为自定义(部署hasura自动生成的)的graphQLAPI提供了访问业务逻辑RestAPI的方式。
例如由RestAPI负责验证、处理或丰富数据,亦或者调用其他API,亦或者用户登录。action可以处理请求和返回值的数据、可以异步返回值graphql客户端。
- 配置
创建action
| Action Definition | 自定义graphQL |
| Type Configuration | 自定义graphQL中用到的模型,入参类型用input修饰,其他类型用type修饰 |
| Webhook (HTTP/S) Handler | RestFul API 地址 必须填写http或https |
| Change Request Options | 设置rest api request,如method 参数映射 |
| Change Payload | 组织rest api body信息,只post需要 |
| Change Response | 返回结果映射 |
代码生成:提供rest api代码模板,例如notejs提供rest api
- 总结:
action仅负责配置自定义grapql api与外部rest api的关系,此时action配置无法对表数据进行新增和修改,只能通过rest api写数据(业务逻辑中再次调用graphQL api),action可以通过返回值关联查询出数据。

授权
需要依赖外部的授权服务器。例如jwt:访问外部的授权服务器,或action,授权结果放在header Authorization,hasura进行鉴权。
使用JWT
| 启动配置项 | HASURA_GRAPHQL_JWT_SECRET |
| jwt claim内容必须包括的数据项 | x-hasura-allowed-roles 用户具有的角色 x-hasura-default-role 默认角色 |
| 请求header携带授权信息 | Authorization Bearer +jwt |
| 其他header | x-Hasura-Role 访问当前graphQL api应具有的角色 |
- 鉴权举例:不具有角色。
-
Authorization
Bearer eyJhbGciOiJIUzI1NiJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6ImFub255bW91cyIsIngtaGFzdXJhLXVzZXItaWQiOiI2IiwieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJ1c2VyMSIsImVkaXRvciJdfX0.NdIKwk9wCpt_6xwag_yQzZTs1zA3P68XCDLF_1egxDM
jwt claim
"x-hasura-allowed-roles", ["user1", "editor"]
"x-hasura-default-role", "anonymous"
"x-hasura-user-id", "6"
访问效果

鉴权举例:具有角色且满足数据权限过滤条件。
Authorization
Bearer eyJhbGciOiJIUzI1NiJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIxIiwieC1oYXN1cmEtdXNlci1pZCI6IjYiLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbInVzZXIiLCJlZGl0b3IiXX19.idFmUt-tPzcw2LkTuHX5MlN-JkEw8aBh6HQIIcLHeRw
jwt claim
"x-hasura-allowed-roles", ["user", "editor"]
"x-hasura-default-role", "anonymous"
"x-hasura-user-id", "6"
权限配置
t_user表 user角色具有select权限,且添加数据过滤条件 id = header中x-hasura-user-id

访问效果

鉴权结果:角色满足但是无数据
| Authorization | Bearer eyJhbGciOiJIUzI1NiJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6ImFub255bW91cyIsIngtaGFzdXJhLXVzZXItaWQiOiI4MCIsIngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciIsImVkaXRvciJdfX0.kVXOMQYpzdKJ44abF_cUXdY8rJFazf4n2MhcOMz5lrQ |
| jwt claim | "x-hasura-allowed-roles", ["user", "editor"] "x-hasura-default-role", "anonymous" "x-hasura-user-id", "80" |
| 访问效果 |
|
生成jwt内容的java代码
io.jsonwebtoken jjwt-api 0.11.5 io.jsonwebtoken jjwt-impl 0.11.5 runtime io.jsonwebtoken jjwt-jackson 0.11.5 runtime static final String jwtSecretString = "S22zAIgXiQmMoywh/jGzm3Tx4o/M74UVarnFKbqNSBc=";
static String jwt() {Map hasuraClaim = new HashMap<>();hasuraClaim.put("x-hasura-allowed-roles", new String[]{"user", "editor"});hasuraClaim.put("x-hasura-default-role", "anonymous");hasuraClaim.put("x-hasura-user-id", "80");SecretKey key = Keys.hmacShaKeyFor(jwtSecretString.getBytes(StandardCharsets.UTF_8));String compact = Jwts.builder().claim("https://hasura.io/jwt/claims", hasuraClaim).signWith(key, SignatureAlgorithm.HS256).compact();Jws claimsJws = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(compact);return compact;} admin和匿名
不是提供公共服务,则需要添加admin环境配置。
- 配置:HASURA_GRAPHQL_ADMIN_SECRET=xxxx
- 请求header添加X-Hasura-Admin-Secret=xxxx,无header则拒绝访问。
匿名访问
- 配置匿名role,配置权限
- 环境配置:admin配置和HASURA_GRAPHQL_UNAUTHORIZED_ROLE=匿名角色名
鉴权
提供基于角色的数据操作权限控制,为角色分配数据表、字段的crud权限。
使用上,必须在request header中携带角色信息,否则角色控制失效。
例如header X-Hasura-Role=user,角色user的权限控制才生效。
docker安装
不使用jwt:
docker run --name chl_hasura_adminsecret -d -p 8080:8080 -e HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:chl_postgre@10.21.4.11:5432/mydb -e HASURA_GRAPHQL_ENABLE_CONSOLE=true -e HASURA_GRAPHQL_ADMIN_SECRET=xxxadminsecret -e HASURA_GRAPHQL_UNAUTHORIZED_ROLE=anonymous hasura/graphql-engine:latest
使用jwt:
以下脚本添加jwt配置,启动失败,网络和官网搜不到原因。最终使用docker-compose.yaml,不报错。
(Environment variable HASURA_GRAPHQL_JWT_SECRET: Error in $: object key > 34: Failed reading: satisfy)
docker-compose.yamldocker run --name chl_hasura_adminsecret_jwt -d -p 8080:8080 -e HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:chl_postgre@10.21.4.11:5432/mydb -e HASURA_GRAPHQL_ENABLE_CONSOLE=true -e HASURA_GRAPHQL_ADMIN_SECRET=xxxadminsecret -e HASURA_GRAPHQL_UNAUTHORIZED_ROLE=anonymous -e HASURA_GRAPHQL_JWT_SECRET="{'type':'HS256', 'key':'S22zAIgXiQmMoywh/jGzm3Tx4o/M74UVarnFKbqNSBc='}" hasura/graphql-engine:latest
version: '3.6'
services:
postgres:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: chl_postgre
POSTGRES_USER: postgres
volumes:
- db_data:/var/lib/postgresql/data
graphql-engine:
image: hasura/graphql-engine:latest
ports:
- "8080:8080"
depends_on:
- "postgres"
restart: always
environment:
HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:chl_postgre@10.21.4.11:5432/mydb
HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
HASURA_GRAPHQL_ADMIN_SECRET: xxxadminsecret
HASURA_GRAPHQL_UNAUTHORIZED_ROLE: anonymous
HASURA_GRAPHQL_JWT_SECRET: '{"type":"HS256","key":"S22zAIgXiQmMoywh/jGzm3Tx4o/M74UVarnFKbqNSBc="}'
volumes:
db_data:
实践中遇到的问题
访问graphql mutation接口时出现invalid query错误
原因为:提交的json中key不可以使用"或'包裹,例如{‘key’:val}{"key":val},这样都会报错。
解决方式:客户端json key加前后缀,对json str进行替换。
var baseInfo = JSON.stringify(this.data.baseInfo).replace("\"prefix_", "").replace("_suffix\"", "")while(baseInfo.includes("prefix_")){baseInfo = baseInfo.replace("\"prefix_", "").replace("_suffix\"", "")}var operationsDoc = `mutation MyMutation {insert_chl_t_base_info_one(object: `+baseInfo+`) {id}}`; jwt配置问题
转为使用docker-compose.yaml文件
其他
Spring-graphQL
Spring提供了对graphQL的支持,负责结合graphQL java与Spring引擎。
开发者需要做的事情:按照graphQL规范定义类型系统、graphQL api;java编写controller,可自由实现业务逻辑。
postgresql客户端工具pgamind
docker安装
docker run --name chl_pgadmin -d -p 8082:80 -e PGADMIN_DEFAULT_EMAIL=123@123.com -e PGADMIN_DEFAULT_PASSWORD=123456 dpage/pgadmin4:latest
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!











