graphql-spec icon indicating copy to clipboard operation
graphql-spec copied to clipboard

[RFC] Collections / CollectionTypeDefinition

Open emadzz opened this issue 3 years ago • 1 comments

TL;DR:

This RFC introduces a new variant of Lists/Arrays that has named entries key-value pairs. Which can be queried exactly like arrays, but a result is an object.

Problem Statement

If a type object has multiple fields of the same type and it makes sense that they are grouped together and be addressed as a collective instead of being addressed individually, with GraphQL you have three ways you can achieve that. Creating a scalar, creating another type, or using an array and somewhere in the documentation mention which position of an array refers to which named entry.

Example

Consider the following requirements:

  1. a Build object consists of 4 Item-slots.
  2. Slot position matters and it should be readable which slots are equipped.
  3. Preferably slots should be grouped together under a common ancestor without any unrelated siblings.
  4. Item slots should not be queried/selected individually, the query either includes all slots or non.
  5. It's possible to specify which Item fields are included.

Initially, the schema may look like this:

type Item {
  id: String!
  name: String!
  icon(size: String): String!
}

type Build {
  id: String!
  slot0Item: Item
  slot1Item: Item
  slot2Item: Item
  slot3Item: Item
}

... but that doesn't satisfy the 3rd and 4th requirements.

Introducing a new type ItemSlots still won't satisfy the 4th requirement:

type Item {
  id: String!
  name: String!
  icon(size: String): String!
}

type ItemSlots {
  slot0Item: Item
  slot1Item: Item
  slot2Item: Item
  slot3Item: Item
}

type Build {
  id: String!
  items: ItemSlots!
}

and using a Scalar it's not possible to meet the 5th requirement.

🧑‍💻 Proposed Solution

A new collection type.

🎬 Behavior

Collections can be queried exactly as if they were an array/list, but instead of returning an array of 0 to entries, it returns finite named entries as specified in the schema.

✏️ Proposed syntax - !

Collections can be defined similarly to how an object type is defined, except fields don't have a type (because all fields are supposed to be of the same type).

collection ItemSlots {
  slot0
  slot1
  slot2
  slot3
}

type Item {
  id: String!
  name: String!
  icon(size: String): String!
}

type Build {
  id: String!
  items: ItemSlots<Item>! # or `ItemSlots<Item!>!` if fields are not nullable.
}

✨ Use cases

  • Allows grouping of fields that share the same type and are supposed to be addressed atomically.
  • Gets rid of unnecessary/repetitive lines in queries to select the same nested fields across multiple fields.

The items field in the above schema can be queried like:

query GetBuild($id: String!, $iconSize: String!) {
  build(id: $id) {
    id
    items {
      name
      icon(iconSize: $iconSize)
    }
  }
}

and the result should look something like this:

{
  "data": {
    "build": {
      "id": "...",
      "items": {
        "slot0": {
          "name": "...",
          "icon": "..."
        },
        "slot1": "...",
        "slot2": "...",
        "slot3": "..."
      }
    }
  }
}

I should probably note that the template structure of this issue was copied from an RFC of @\twof. I just found the template very clean and the structure fits my proposal as well. :))

emadzz avatar Apr 02 '22 09:04 emadzz

I do not quite understand the purpose and benefits. The whole reasoning is based on these 'requirements', which are quite questionable. Like number 4:

  1. Item slots should not be queried/selected individually, the query either includes all slots or non.

why this thing is so necessary (in certain cases?) that it warrants a new concept and new syntax?! Is it like transactional - all or nothing? all fields or none? What is the case when it's critical?!

and req 5, along with the suggested benefit:

Gets rid of unnecessary/repetitive lines in queries to select the same nested fields across multiple fields.

there is a thing already that does this. It's called Fragments

rivantsov avatar Apr 05 '22 05:04 rivantsov