RFC: Provide static types for nested components in GraphQL schema

Change Description:
Provide static types for nested components in the GraphQL schema available from https://gapi.storyblok.com/v1/api

Reasons for change:
Static types for nested components are necessary in order to be able to generate type-safe code from a GraphQL schema in your language of choice (e.g. Java/Kotlin/TypeScript etc.) using industry-standard tools such as graphql-codegen.

Examples:
Let’s say we have a content-type page which takes 1…N components from the group layout > sections, in which the Generic Section takes 1…N components from the group layout > elements:



Then let’s say we have a Landing Page instance of the content-type page, which some Generic Sections with some elements like feature, grid , cta etc.:

Already using the GraphiQL explorer, we can see that we can’t introspect any further than sections:

And even worse, using graphql-codegen to generate some TypeScript for our content model, we can see that a PageItem > PageComponent doesn’t even have sections, all it has is an untyped body field:


Note: My examples use TypeScript but the same would be true for Java/Kotlin/.NET/whatever.

Effect if not implementing change:

  • Users won’t be able to generate type-safe code of their content model/schema
  • Users will have to manually keep their content-model JSON in-sync with their code models, instead of relying on industry-standard type-safe code generation

Links:

Suggestions for implementation:
Some other headless-CMS solutions on the market can generate a GraphQL schema like below, using union types for polymorphism:

type Page {
  name: String
  slug: String
  content: [PageComponent]!
}

type PageComponent {
  sections: [PageSection]!
}

union PageSection = HeroSection | GenericSection | FaqSection

type GenericSection {
  title: String
  elements: [GenericSectionElement]!
}

union GenericSectionElement = FeatureElement | GridElement | CtaElement

As a bonus, one can then also query a page and cover all cases using fragments or inline fragments:

fragment FeatureElementInfo on FeatureElement {
  title: String
  text: String
}

fragment GenericSectionInfo on GenericSection {
  title
  elements {
    ...FeatureElementInfo
    ...GridElementInfo
    ...CtaElementInfo
  }
}

query GetPage($id: String!) {
  Page(id: $id) {
    content {
      sections {
        ...HeroSection
        ...GenericSection
        ...FaqSection
      }
    }
  }
}