超图
如果我们重新审视 API 的作用,我们会发现,作为客户端和服务端数据的桥梁,API 解析客户端的请求,从服务端某个数据源(可能是数据库,也可能是其他服务的数据等),获取相应的数据,然后按照 API 的约定返回合适的结果。
既然 API 的目的是提供数据,而数据往往有其严苛的 schema,同时 API 的 schema 大多数时候就是数据 schema 的子集,那么,我们是不是可以从数据 schema 出发,反向生成 API 呢?
但不同数据源协议不同,如 对数据库而言,不同数据库有不同SQL方言,对REST api和gql api协议也不同。
而且聚合不同类型数据源的数据,也是API的常见用例。因此,需要先将不同协议的schema,统一为一种协议,然后再行编排,生成API,才能符合绝大多数应用场景。
统一协议

gql作为一种强类型API语言,非常适合作为该统一协议。
- 借助Prisma引擎,将不同类型数据库的schma转成了gql schema,统一了不同数据库的sql方言。 
- 同时,利用openapi specification规范,将rest api也转成了gql schema 
- 而graphql api,本身就是gql协议,具备gql schema 
我们将上述各数据源转换而来的GQL SCHEMA,称为子图。
各个子图合并后的产物称为超图,它本质上也是GQL SCHEMA,只不过聚合了不同的数据源。图中将3种类型数据源 数据库、REST API以及gql api产生的超图,都合并到了这个超图中。
但为了避免不同数据源相同表名或接口合并到超图后,产生冲突,因此需要给不同子图加上命名空间,一示区分。
上述所有的步骤都是自动执行的,无需手工编写gql schema,极大提升开发体验。
而实现上述自动化的核心需要依赖gql的内省能力。
Prisma
接着我们学习下prisma mode到gql scheama的转换规则。
prisma的核心原理见 数据库

首先,prisma model与数据库建表语句等价。且prisma model能转换成多种数据库的建表语句。
例如,这里的prisma model转换为了pgsql的建表语句。
model Todo {
  id        Int      @id @default(autoincrement())
  title     String
  completed Boolean  @default(false)
  createdAt DateTime @default(now())
  content   String?  @default("")
  test      Int      @default(1)
}接着,我们看下prisma model到gql schema的转换规则。
这里有一个todo模型,右侧是其转换后的schema可视化展示。
规则为:命名空间+方法名+表名。命名空间是为了区分不同数据库实例的相同表名。
其中查询有如下方法:
- findFirst:返回列表中符合条件的第一条记录 
- findMany:返回记录列表 
- findUnique:根据主键或唯一键查询一条记录 
- aggregate:聚合数据,包括 avg、count、sum、min、max 
- groupBy:聚合函数,根据一或多列对结果集分组 
变更有如下方法:
- createOne:创建一条记录,对应 sql 中的 insert 
- createMany:创建多条记录 
- deleteMany:批量删除记录,对应 sql 中的 delete 
- deleteOne:删除一条记录,对应 sql 中的 delete 
- updateMany:更新多条记录,对应 sql 的 update 
- updateOne:更新一条记录,对应 sql 的 update 
- upsertOne:更新或插入一条记录 
里面还包含两个原生方法,用于编写复杂SQL,适用于上述方法无法覆盖的场景。
- queryRaw:执行查询类sql 
- executeRaw:执行创建、变更类sql 
对于有关联关系的模型,其函数名称一致,但入参会更加复杂,这块需要前往prisma官方文档查看。
RSET API
飞布除了支持数据库数据源外,还支持REST 数据源。

如图所示,是OAS3.0规范的示例,可以看到它也定义了入参和出参,并且支持类型,可以转换为gql scheme。
所以只需要提供OAS文件,飞布就能将rest api转变为子图,然后合并到飞布的超图中。
注意看,子图没有命名空间前缀,超图中增加了前缀PET。
接着,我们看看OAS生成GQL SCHEMA子图的详细规则:
- paths中请求类型对应gql schema中的query:get对应query,POST/put/patch对应mutation。例如,pet/{petid} get 转换为query类型。 
- paths的operationid,对应gql schemla 中的根字段名称,或者说函数名称,如果它为空,则用path去除特殊字符后函数名。例如getpetbyid。 
- parameters入参对应gql schemla 中函数的入参。例如,petid为integer类型,对应到gql schema为Petid int类型,required true,对应为!. 
- response出参对应gql schemla 中函数的返回值。例如,pet schema转换为pet 类型。id字段为标量interge类型,转换为int。category为对象,在这里也是对应为cateory对象。 
架构图
最后我们查看下架构图,重点关注超图部分。

在这里,飞布主要做了2件事:
- 用graphql统一协议,屏蔽数据库、REST API等不同类型数据源的协议。其中又用prisma屏蔽了各数据库sql方言的差异。 
- 自动内省自行转换协议:将rest api的oas文件转换为graphql,自动内省数据库和graphql 数据源,避免手动编写graphql。 
至此,你已经掌握了飞布最核心的概念——超图。
最后更新于
这有帮助吗?
