Skip to content

GraphQL ​

POST /graphql。queryengine.http.base-path 会加在路径前面,例如 /api/graphql。可选请求头 X-QueryEngine-Schema 只覆盖这一次调用,并据此选择那一份 access 名单。

schema 在第一次查询某个 schema 时,按该 schema 的 access 名单懒生成。列来自物理表的结果集元数据,使用物理列名,不会做驼峰转换。没有登录。

bash
curl -s -X POST http://127.0.0.1:8080/graphql \
  -H 'Content-Type: application/json' \
  -d '{ "query": "{ User(id: 38710) { id name tag } }" }'
json
{
  "data": { "User": { "id": 38710, "name": "Tommy", "tag": "student" } },
  "extensions": { "code": 200, "message": "success" }
}

请求 ​

请求体是 JSON 对象:

字段要求
query必填,GraphQL 文档字符串
variables省略或 JSON 对象
operationName省略,或文档里某个操作的名字
json
{
  "query": "query ($uid: Long!) { User(id: $uid) { id name } }",
  "variables": { "uid": 38710 },
  "operationName": null
}

根字段名是 access 里登记的拼写,例如 User。GraphQL 按这个字段名匹配。

标量 ​

列参数只有两种类型:

  • 整数列(BIGINT、INTEGER、SMALLINT、TINYINT):自定义标量 Long
  • 其他列:String

这些列参数不使用规范里的内置标量 ID、Int、Float、Boolean。变量类型必须和参数一致。

声明结果
$uid: ID!Unknown type 'ID'
$uid: Int!Variable type mismatch,参数实际类型是 Long
$uid: Long!可以通过校验

查询里直接写数字字面量(User(id: 38710))不需要声明变量类型。分页参数 page、count 是内置 Int。关联参数 on 是 String!。

查询字段 ​

每张已登记的表有两个根字段:

字段返回参数
User(...)一行,或 null各列的等值条件
UserList(page, count, ...)数组同上,另加分页

若另一张已登记的表刚好叫 UserList,列表字段改名为 UserRows。

列参数是等值过滤,对应 NestQL 里的 "列": 值。比较、IN、LIKE 不在 GraphQL 参数里,那些写在 NestQL。命中两行及以上时是 400,与 NestQL 的对象查询相同。没有行时该字段为 null。

page 从 0 开始。page 和 count 是分页参数,名字正好是 page 或 count 的列不会同时成为过滤参数。列表省略 count 时使用引擎的 defaultPageSize(默认 10)。page 省略时为 0。软限制与 NestQL 分页 相同。

选择集里的列会变成 @column。没选列、只选了关联字段时,父查询会补上 id,供关联使用。

bash
curl -s -X POST http://127.0.0.1:8080/graphql \
  -H 'Content-Type: application/json' \
  -d '{"query":"query ($uid: Long!) { User(id: $uid) { id name Moment(on: \"userId\") { id content } } }","variables":{"uid":38710}}'
bash
curl -s -X POST http://127.0.0.1:8080/graphql \
  -H 'Content-Type: application/json' \
  -d '{"query":"{ UserList(name: \"Tommy\", count: 5) { id name } }"}'

嵌套 ​

子字段名如果是另一张已登记的表,并且带了必填参数 on,就再查一次列表。on 是子表里指向父行 id 的物理列名,必须是合法标识符。这是按该列等值再查,不是 JOIN。

graphql
{
  User(id: 38710) {
    id
    name
    Moment(on: "userId", page: 0, count: 10) {
      id
      content
    }
  }
}

关联上的 page、count 可省略。省略 count 时这一层用 100,省略 page 时用 0。父行没有 id 时,关联结果是空数组。

与父表同名的字段,或与某个物理列同名的表,不会再生成关联字段,以免覆盖列。

变更 ​

每张表有三个 mutation。参数名是物理列名。返回对象上的 affected 对应该次写入的 count。选择集里没出现的列不会回读。表本身已有名为 affected 的列时,使用那个列,不再另加影响行数。

graphql
mutation {
  createUser(id: 9, name: "Ada") { id name affected }
  updateUser(id: 9, name: "Ada Lovelace") { name affected }
  deleteUser(id: 9) { id affected }
}
字段参数主键
createUser各列,均可省略到只剩要插入的字段可省略,由数据库生成
updateUser要修改的列id 必填,类型与该列一致;表上没有 id 列时为 Long!
deleteUser只有 idid 必填

update / delete 缺少 id 会失败。GraphQL 这一层的主键列固定是 id,与库构建器里的 idColumn(...) 相互独立。

错误与 schema ​

失败时 body 里有 GraphQL errors。每条错误的 extensions.code,以及顶层 extensions.code,使用和 NestQL 相同的数字:400 语法或校验,403 无权,500 SQL。整次调用没有成功数据时,HTTP 状态与这个数字相同;已经返回了部分 data 时 HTTP 仍是 200。说明见 错误码。

未出现在 access 名单里的表不会进入 schema。查询它是 GraphQL 校验错误,code 为 400。

graphql
{ __schema { queryType { fields { name } } } }

可以看当前 schema 已经生成的根字段。登记新表之后,下一次请求会按新的名单重新生成。名单为空时,查询根上只有占位字段 _empty。