Почему требуются грани в соединении Relay/GraphQL?

В конфигурации схемы Relay/GraphQL отношения "один ко многим" (с разбивкой на страницы) указаны как в примере учебника

type ShipConnection {
  edges: [ShipEdge]
  pageInfo: PageInfo!
}
type ShipEdge {
  cursor: String!
  node: Ship
}

Однако соединение "один к одному", сделанное ShipEdge, кажется излишним. Почему мы не можем переместить курсор на ShipConnection и сохранить массив идентификаторов Ship как ребра?

type ShipConnection {
  edges: [Ship]
  pageInfo: PageInfo!
  cursor: String!
}

Какими проектными решениями требовался один дополнительный объект для каждого edge в отношениях "один ко многим"?

Ответ 1

Поле edges предоставляет вам место для размещения данных на каждом фронте. Например, вы можете разместить поле creator или priority там, где указано, кто добавил ребро и насколько важны отношения, соответственно.

Если вы не требуете такой гибкости (или других функций, которые вы получаете при подключении, таких как разбиение на страницы), вы можете использовать простой тип GraphQLList. См. этот ответ, чтобы узнать больше о различиях между соединениями и списками.

Ответ 2

Есть две причины для края, о котором я могу думать:

  • Это место для атрибутов, специфичных для края. Например, если у вас есть User, который принадлежит ко многим Group s, в реляционной базе данных у вас будет таблица UserGroup с user_id и group_id. Эта таблица может иметь дополнительные атрибуты, такие как role, joined_at и т.д. GroupUserEdge будет тогда местом, где вы могли бы получить доступ к этим атрибутам.

  • Найдите место для курсора. Важным выводом является то, что каждый node в соединении имеет курсор (поэтому у вас не может быть только один курсор на самом соединении). Зачем нам (Relay) нужен курсор для каждого node? Поскольку Relay интеллектуально объединяет требования к данным из всего вашего приложения, он может уже иметь соединение с теми же параметрами, которые вы запрашиваете, но недостаточно записей. Чтобы получить отсутствующие данные, он может запрашивать данные в соединении после некоторого курсора.

    Я понимаю, что это может сбивать с толку, учитывая, что в базах данных есть курсоры, и есть только один курсор для каждого запроса. Реле-соединение действительно не является запросом, а скорее набором параметров, которые идентифицируют запрос. Курсор границы соединения - это набор параметров, которые определяют позицию в соединении. Это более высокий уровень абстракции, чем чистый курсор запросов (помните, что ребра должны иметь возможность идентифицировать позицию даже по соединению, которое может не быть запросом БД или быть скрытым сторонней системой). Из-за этой требуемой гибкости один курсор для соединения будет недостаточным.