1.5: Schema Language

1.5: Schema Language

Thus far, we have focused on the GraphQL query language, and we've noted at various points the imaginary types we presume to be part of the schema for our application, defined at the server. Let's delve into the specifics of how such a schema would be defined.

It's appropriate to emphasize again that GraphQL is a specification only. The data structures in backend storage (e.g., in MySQL), and the way that data is resolved into a query response, is up to the particular application and its implementation of the specification. What we're discussing here is an agnostic language (itself part of the specification) for expressing a type system, which any GraphQL runtime can consume in order to validate queries and responses.

Let's look at a type schema that would support the imaginary queries and mutations we've looked at:

enum MythEnum {
    GREEK
    EGYPTIAN
    CHINESE
    NORSE
    CELTIC
    BABYLONIAN
}

enum DomainEnum {
    THUNDER
    SUN
    WAR
    LOVE
    WISDOM
}

enum HeightUnitEnum {
    INCH
    FOOT
    METER
}
type God {
    id: ID!
    name: String!
    domain: DomainEnum
    mythology: MythEnum!
}

type PageInfo {
    currentPage: Int!,
    totalPages: Int!
}

type AllGodsPage {
    pageInfo: PageInfo,
    gods: [God!]!
}

type Food {
    id: ID!
    label: String!
    cuisine: String
}
type Person {
    id: ID!
    name: String!
    height(unit: HeightUnitEnum = INCH): Float
    favoriteFoods(limit: Int = 10): [Food!]!
    friends: [Person!]!
    createdAt: String!
}

type Query {
    person(id: ID!): Person
    allGods(domain: DomainEnum, page: Int, limit: Int): AllGodsPage
}
input PersonInput {
    name: String!
    height: Float
}

type Mutation {
    createPerson(
        person: PersonInput!, 
        favoriteFoodIds: [ID], 
        friendIds: [ID]
    ): Person
}

You can delve into the GraphQL documentation to learn about the details of the type system, including syntax for some concepts not represented here. The above example, however, is likely fairly self-explanatory. (And a major detail to note is how similar the syntax is to query syntax!) Here are some highlights:

  • True to the concept we've discussed of fields nested in other fields, the main definitions are types with fields, each of which has a defined scalar type or another complex type. Note the definitions of the root Query and Mutation types.
  • Note the enum declaration that can define the values of an enumeration.
  • Also note the input declaration, which is in all respects like a type but defines a type that can be used as input for an argument.
  • The syntax [Person!]! looks tricky but is fairly intuitive in the end. The ! inside the bracket declares that every value in the array must be non-null, while the one outside declares that the array value itself must be non-null (e.g., an empty array).

Type Resolution

The logic for how data is fetched and formatted according to a schema, and how such logic is mapped to particular types, is up to the GraphQL runtime implementation. Any implementation, however, follows a conceptual flow that should make sense in light of our understanding of nested fields: A "resolve" operation associated with the root Query or Mutation type is performed, which examines each field specified in the request. For each field that resolves to a complex type, a similar "resolve" is done for that type, and so on until everything has resolved into scalar values.

We'll see how Magento integrates directives into the schema definition language itself, with "resolver" classes defined inline.

Interfaces and Unions

Interfaces and Unions are schema language constructs that Magento customizes with specific new functionality, so you should familiarize yourself with them.

Complete and Continue