Skip to content

Instantly share code, notes, and snippets.

@AugustoCalaca
Forked from robrichard/defer-array.md
Created December 31, 2019 17:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AugustoCalaca/f13e5b85f096b3b04a84ddf74e568413 to your computer and use it in GitHub Desktop.
Save AugustoCalaca/f13e5b85f096b3b04a84ddf74e568413 to your computer and use it in GitHub Desktop.
Relay Compatible `@defer` & `@stream`

Using @defer under an array field will return multiple patches. Patches are unique combinations of label and path

{
  items {
    id
    ...frag @defer(label: "my-label")
  }
}

fragment frag on Item {
  title
}

Initial result:

{
  "data": {
    "items": [
      { "id": 1 },
      { "id": 2 },
      { "id": 3 },
    ]
  }
}

Patches:

  • Multiple Patches
{
  "label": "my-label",
  "path": ["items", 0],
  "data": { "title": "chair" }
}
{
  "label": "my-label",
  "path": ["items", 1],
  "data": { "title": "table" }
}
{
  "label": "my-label",
  "path": ["items", 2],
  "data": { "title": "lamp" }
}

Fields that are on both deferred and non-deferred fragments are returned twice.

{
  item {
    title
    ...frag @defer(label: "my-label")
  }
}

fragment frag on Item {
  title
}

Initial result:

{
  "data": {
    "item": {
      "title": "chair"
    }
  }
}

Patch:

{
  "label": "my-label",
  "path": ["item"],
  "data": {
    "title": "chair" 
  }
}

Deferred fields are not returned at all in the initial response. This differs from the Apollo defer implementation, in which deferred fields are returned as null, and must be nullable in the schema.

{
  item {
    id
    ...frag @defer(label: "my-label")
  }
}

fragment frag on Item {
  title
}
  • Deferred field is not present
{
  "data": {
    "item": {
      "id": 1
    }
  }
}

Queries can contain the same field with multiple streams. All fields that are not streamed are returned in the initial response, with all results that are streamed for items below the initial_count. Then one patch is returned for every path/label combination.

query HeroNameQuery {
  hero {
    friends {
      id
    }
    ...FragA
    ...FragB
    
  }
}

fragment FragA on Character {
  friends @stream(label: "nameLabel", initial_count: 1) {
    name
  }
}

fragment FragB on Character {
  friends @stream(label: "appearsInLabel", initial_count: 2)  {
    appearsIn
  }
}

Initial Response:

{
  "data": {
    "hero": {
      "friends": [
        {
          "id": "1000",
          "appearsIn": [
            "NEWHOPE",
            "EMPIRE",
            "JEDI"
          ],
          "name": "Luke Skywalker"
        },
        {
          "id": "1002",
          "appearsIn": [
            "NEWHOPE",
            "EMPIRE",
            "JEDI"
          ]
        },
        {
          "id": "1003"
        }
      ]
    }
  }
}

Patches:

{
  "data": {
    "name": "Han Solo"
  },
  "path": ["hero", "friends", 1],
  "label": "nameLabel"
}
{
  "data": {
    "appearsIn": [
      "NEWHOPE",
      "EMPIRE",
      "JEDI"
    ]
  },
  "path": ["hero", "friends", 2],
  "label": "appearsInLabel"
}
{
  "data": {
    "name": "Leia Organa"
  },
  "path": ["hero", "friends", 2],
  "label": "nameLabel"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment