探索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}}}"}

hasura配置演示

数据模型-维护

探索graphQL-hasura引擎_第1张图片

数据模型-外键关系

探索graphQL-hasura引擎_第2张图片

数据模型-角色访问控制

探索graphQL-hasura引擎_第3张图片

grapqlAPI-查询数据

探索graphQL-hasura引擎_第4张图片

grapqlAPI-编辑数据

探索graphQL-hasura引擎_第5张图片

action业务逻辑01-配置graphql和模型

探索graphQL-hasura引擎_第6张图片

action业务逻辑02-访问的rest接口url

探索graphQL-hasura引擎_第7张图片

action业务逻辑03-request参数转换

探索graphQL-hasura引擎_第8张图片

action业务逻辑04-response转换

探索graphQL-hasura引擎_第9张图片

action业务逻辑05-调用暴露的graphql

探索graphQL-hasura引擎_第10张图片

开门见山说重点

个人理解

  • 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实现。

探索graphQL-hasura引擎_第11张图片

  • 新增数据

可创建单条,多条数据,如单个商品、多个商品

可以同时创建具有外键关系的多条记录,如商品和类目有外键关系,可创建类目同时创建一个商品,要求外键不赋值

例如:执行效果,新建类目记录,商品外键类目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 {
      id
      t_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

返回结果映射

权限:哪些角色可以访问自定义的action
关联:rest api 返回值 和 db中某个模型 存在关联,如返回值userId 与 user表id关联,可以配置关联关系,将user信息作为返回值。

代码生成:提供rest api代码模板,例如notejs提供rest api

  • 总结:

action仅负责配置自定义grapql api与外部rest api的关系,此时action配置无法对表数据进行新增和修改,只能通过rest api写数据(业务逻辑中再次调用graphQL api),action可以通过返回值关联查询出数据。

探索graphQL-hasura引擎_第12张图片

授权

需要依赖外部的授权服务器。例如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"

    访问效果

    探索graphQL-hasura引擎_第13张图片

    鉴权举例:具有角色且满足数据权限过滤条件。

    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

    探索graphQL-hasura引擎_第14张图片

    访问效果

    探索graphQL-hasura引擎_第15张图片

鉴权结果:角色满足但是无数据

Authorization

Bearer eyJhbGciOiJIUzI1NiJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6ImFub255bW91cyIsIngtaGFzdXJhLXVzZXItaWQiOiI4MCIsIngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciIsImVkaXRvciJdfX0.kVXOMQYpzdKJ44abF_cUXdY8rJFazf4n2MhcOMz5lrQ

jwt claim

"x-hasura-allowed-roles", ["user", "editor"]

"x-hasura-default-role", "anonymous"

"x-hasura-user-id", "80"

访问效果

探索graphQL-hasura引擎_第16张图片

生成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:[email protected]: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 run --name chl_hasura_adminsecret_jwt -d -p 8080:8080 -e HASURA_GRAPHQL_DATABASE_URL=postgres://postgres:[email protected]: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

docker-compose.yaml

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:[email protected]: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 [email protected] -e PGADMIN_DEFAULT_PASSWORD=123456 dpage/pgadmin4:latest

你可能感兴趣的:(技术思考总结,graphql,hasura)