Laravel Lighthouse 很可惜地无法支持 React Relay 的游标连接
React Relay
反应中继
这是一个GraphQL客户端,网址是https://relay.dev/。
除了Apollo客户端,作为另一个代表的选择,目前正在试用Relay。
我想选择继电器的原因(目前是这样认为)
对于React Relay的框架,由于其提高了生产力并减少了代码维护的量,因此,现在正是全力采用它的阶段。
作为与Apollo Client进行比较的一点,Relay对GraphQL服务器端的规范进行了限制。
-
- 識別子(ID)の定義の仕方
-
- コネクション(ページ情報)の定義の仕方 (cursor connection)
-
- mutation 引数の定義の仕方
- などなど…
有时人们对于限制一词会产生负面印象,但正因为有这些限制,我们能够提高对象重新获取的效率,在分页方面达到所需的模式定义,并减少设计和实现过程中需要考虑的事项(可能会减少)。
关于标识符,这些Relay的限制直接被写入GraphQL官方文档作为最佳实践。
灯塔:基于Laravel的GraphQL服务器。
Lighthouse是一个可以与Laravel集成的GraphQL服务器。
https://lighthouse-php.com/
提供了许多与Eloquent集成的指令,如果仅需要CRUD操作,代码量也较少,似乎可以构建GraphQL端点。
(必须提供关联定义等内容,不能完全不写。)
这个指令非常简单,只需要写@hasMany之类的指令,就可以根据Relay连接的定义生成模式。
例如,假设我们写了这样的模式。
type User @model {
id: ID! @globalId
name: String!
projects: [Project!] @hasMany(type: "connection", relation: "projects")
}
type Project @model {
id: ID! @globalId
name: String!
status: ProjectStatus!
createdAt: DateTime! @rename(attribute: created_at)
updatedAt: DateTime! @rename(attribute: created_at)
}
灯塔解释指令的结果如下(相关部分摘录):
type User implements Node {
id: ID!
name: String!
ownerName: String!
iconUrl: String
projects(
first: Int!
after: String
): ProjectConnection
}
interface Node {
id: ID!
}
type ProjectConnection {
pageInfo: PageInfo!
edges: [ProjectEdge]
}
type ProjectEdge {
node: Project
cursor: String!
}
type Project implements Node {
id: ID!
name: String!
status: ProjectStatus!
createdAt: DateTime!
updatedAt: DateTime!
}
在構築GraphQL終點時,已經考慮到了Relay的限制條件,同時還可以使用Laravel的資源,這樣可以高效地建立GraphQL終點!
不过,没有对游标连接提供支持。
在Lighthouse的文件中,有以下的描述,被认为是非常令人遗憾和致命的。
到目前为止,Lighthouse不支持实际的基于光标的分页功能,详情请参阅https://github.com/nuwave/lighthouse/issues/311。在底层,”光标”被解码为页偏移量。
根据此问题的讨论,似乎没有计划对其进行任何处理。
确认连接的行为。
各种模式和架构等
假设在RDB中存储了以下的用户表和记录。
`users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
)
名称是使用php faker随机生成的。
假设有以下的GraphQL模式。
(model等指令是Lighthouse独有的。)
type User @model {
id: ID! @globalId
name: String!
}
type Query {
users: [User!]! @paginate(type: "connection")
}
光标连接的查询
首先,让我们尝试发送以下查询。(尚未指定光标。)
query users {
users(first: 3) {
pageInfo {
count
currentPage
total
}
edges {
cursor
node {
id
... on User {
name
}
}
}
}
}
这个结果如下所示。
{
"data": {
"users": {
"pageInfo": {
"count": 3,
"currentPage": 1,
"total": 10
},
"edges": [
{
"cursor": "MQ==",
"node": {
"id": "VXNlcjox",
"name": "若松 修平"
}
},
{
"cursor": "Mg==",
"node": {
"id": "VXNlcjoy",
"name": "藤本 千代"
}
},
{
"cursor": "Mw==",
"node": {
"id": "VXNlcjoz",
"name": "廣川 舞"
}
}
]
}
}
}
我将使用第二个用户(id=”VXNlcjoy”)返回的游标来指定,并尝试发送一个查询以请求在此游标之后的数据。
query users {
users(first: 3 after: "Mg==") {
pageInfo {
count
currentPage
total
}
edges {
cursor
node {
id
... on User {
name
}
}
}
}
}
这个结果与之前的查询完全没有变化。
也就是说,即使在后面指定了游标,它也没有起作用。
希望的动作是,排除第一个用户(id=”VXNlcjox”),然后返回第2、3、4个用户,但确实没有支持游标连接。
如果不是Relay,可以使用paginator。
在使用 Relay 的情况下,光标连接是必需的,但在不使用 Relay(例如使用 Apollo Client)的情况下,没有这个限制。
Lighthouse 还支持分页器(paginator)除了光标连接之外。
这是一种通过指定页面号进行分页的功能。
type Query {
users: [User!]! @paginate(type: "paginator")
}
我能够按照以下的查询语句编写,并且它按照我期望的方式正常运作了。
query users {
users(first: 3 page: 2) {
paginatorInfo {
count
currentPage
total
currentPage
}
data {
id
name
}
}
}
寻找一个支持Relay的简便GraphQL服务器…
我也考虑到了利用Laravel这个框架以及轻松地构建GraphQL服务器的优点,感觉不错。但是考虑到Relay的前提条件,似乎有些困难。有些可惜。
现在我正在开始调查Harura,可能会是一个好的选择。