Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 818
Ryan-Neal Mes Avatar asked Mar 21 '17 21:03

Ryan-Neal Mes


People also ask

What are edges and nodes in GraphQL?

All of this is a lot of words (and excuses to post pictures of Space Shuttles) to say in a nutshell: the difference is that a node is a specific piece of data whereas edge allows you to access and use the relationship between that data and others as well. Use a node query if you just want the data.

What does edges mean in GraphQL?

The circles in the graph are called “nodes” and the lines of the graph are called “edges.” An edge is a line that connects two nodes together, representing some kind of relationship between the two nodes.

What is the purpose of a GraphQL schema?

A GraphQL schema is a description of the data clients can request from a GraphQL API. It also defines the queries and mutation functions that the client can use to read and write data from the GraphQL server. In other words, you specify your client or application UI data requirements in your GraphQL schema.

What does node mean in GraphQL?

In the GraphQL specification, the node query is a query that takes only an ID and returns the object corresponding to that ID. In a REST API, this is similar to a GET request that fetches an object by ID, but with an important difference: the node query does not require the type of that object to be specified.


3 Answers

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.

like image 154
Goblinlord Avatar answered Oct 19 '22 09:10

Goblinlord


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.
like image 44
Andrew Ingram Avatar answered Oct 19 '22 10:10

Andrew Ingram


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!

like image 31
browserless Avatar answered Oct 19 '22 09:10

browserless