What is the reason for having edges and nodes in a connection in your graphql schema?
Asked Answered
M

3

15

I am trying to understand more complex graphql apis that implement the Relay Cursor Connections Specification

If you look at the query below that I run on the github graphql api explorer

{
  repository(owner: "getsmarter", name: "moodle-api") {
    id
    issues(first:2 ) {
      edges {
        node {
          id
          body
        }
      }
      nodes {
        body
      }
      pageInfo {
        endCursor
        hasNextPage
        hasPreviousPage
        startCursor
      }
      totalCount
    } 
  }
}

Notice it has the fields edges and nodes.

Why does github have an additional field called nodes in their api? Why don’t they just use the edges field since you can get the same data from edges? Is this just for convenience?

Mayer answered 21/3, 2017 at 21:31 Comment(2)
this might be helpful #42623412Wysocki
Some background information: graph.cool/blog/connections-edges-nodes-relay-tioghei9goEvelineevelinn
S
17

If we look at the general structure of the common connection implementation you typically have the following: TypeA -> TypeAToTypeBConnection (usually a field on TypeA with a name like typeBConnection) -> TypeAToTypeBEdge (usually field of name on connection with name edges) -> TypeB (usually field name on an edge with name node)

A -> connection -> edges -> B

Connection types will normally have fields containing information which is specific to the entire connection which is typically paging information, total counts, etc.

Edge types normally have fields which have information which is specific to that connection but not common to all nodes. The most common field in this case is cursor which represents the nodes ‘location’ in the connection which is not a globally unique ID but a way to return to that location in the connection.

Node type is normally just the type which the connection goes too which contains no connection specific information

In the case of github’s API the Edge type has the commonly implemented cursor field which can be used as a reference within that connection later. They also have a field which bypasses the edge type in the case you don't need the cursors. This is why you see both edges and nodes fields directly off the connection type.

To see these cursor fields you can send the following query to see what I am talking about:

{
  repository(owner: "getsmarter", name: "moodle-api") {
    issues(first:2 ) {
      edges {
        cursor
        node {
          id
        }
      }
    }
  }
}

For more detail on this style of connection take a look here: https://facebook.github.io/relay/graphql/connections.htm

EDIT - Additional response: The purpose of allowing access to both an edge type and a node type right at the connection could be for, at least, 2 reasons which I can think of. Firstly, for the convenience of those using the API when their use case does not require cursors. Second, there might be a case in which, depending on the query sent, they may not need to ever even generate cursors. The second would likely be minimal savings in CPU time and would probably be more trouble than it is worth.

Having implemented cursors in a GraphQL endpoint myself in the past, once you get over the how, the actual generation of them is not really all that difficult. It is simply a matter of serializing a few key pieces of information. It also might be worth noting, it is pretty trivial to provide both (A->conn->edge->B and A->conn->B) once you have already created the Edge type.

As I do not work for Github, I can’t tell you what exact intention was. However, I would most definitely think it is the first reason… simply developer convenience.

Schriever answered 22/3, 2017 at 5:1 Comment(3)
Thanks for the detailed answer, but this doesn't actually answer the question. I want to know why nodes are included at the same level as edges. Specifically Github's api. Is it just a convenience? I have read the spec already and understand that an edge has a cursor and a node, but why is there a nodes collection at the same level as edges on the github api? I am leaning towards @griffith_joel's answerMayer
I thought the statement "They also have a field which bypasses the edge type in the case you don't need the cursors. This is why you see both edges and nodes fields directly off the connection type." would be sufficient and I apologize if that wasn't clear. I edited my answer to provide what I hope expands this for clarity.Schriever
I'm late, but after reviewing this answer I'm left with a question. The difference between using node or edge, beyond possible extra fields in the relationship that edge could provide, is: Node will always return all the data of the connection, while edge will additionally provide a cursor to work the "paging" of the related node on that connection (thus having a pagination of the connection and another independent of the edge-node)?Success
E
14

A node is always the same, regardless of how you get to it. The edge is metadata about that node in the context of the connection, usually just the cursor, but you could also add things like a relevancy score if your connection represented a search query. This data shouldn't exist on the node itself, because it makes no sense in a different context.

Terminology:

  1. Node, represents an entity. In a diagram of circles connected by lines, these would be the circles.
  2. Edge, connects two nodes together, may include metadata. In the diagram, these would be the lines.
  3. Connection, a paginated list of nodes. In the diagram, this would be a collection of lines.
Epigenous answered 21/3, 2017 at 23:50 Comment(0)
Q
2

It's likely just a convenience for them since they probably have some crazy queries and it reduces object lookup in JavaScript. Edges will also contain a cursor property as well as a node property, which they likely don't need everywhere, and therefore another benefit of having a top-level node field.

I should also note that the edge/cursor convention is strongly geared to a Relay specific environment, and furthermore a cursor-based paging system where you can only move by a single index/page. If your desire is to create a more legacy-based paging system, then you don't have to implement this type of paging.

A use-case that breaks cursor-paging is if clients want to jump to page 5, and are on page 1, which isn't possible in Relay since cursors are opaque, and are the basis for "where" in a collection you're currently at.

Hope that helps!

Quint answered 21/3, 2017 at 22:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.