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随机生成的。

idname1若松 修平2藤本 千代3廣川 舞4宮沢 浩5小泉 涼平

假设有以下的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,可能会是一个好的选择。

广告
将在 10 秒后关闭
bannerAds