Linking Multiple GraphQL Types

Connect multiple GraphQL types using the @materializer directive

The @materializer directive is a custom StepZen directive for combining data returned from two types into one. It's useful for when you're making a call to two separate endpoints, separate backends or assembling multiple GraphQL types from a nested JSON response.

Configuration Properties

query (required)

query determines the name of the query within the GraphQL schema that will be used to populate the data within your type. For example, if a type Location has a field weather that will be populated with information from a query called weatherReport, then you could set it up like the following type.

type Location {
  city: String
  country: String!
  ip: String!
  latitude: Float!
  longitude: Float!
  weather: WeatherReport @materializer(query: "weatherReport")
}

Note that the type for the field (i.e. weather) needs to match the return type of the query (i.e. weatherReport). If the query (weatherReport in this case) returns an array of results, the type of the weather property can be set to [WeatherReport] to return all the results. If the type of the property is a single type instance but the result of the query is an array of results, then only the first result will be returned.

arguments (optional)

In some cases, the field names of type will not exactly match the arguments needed for the query. The arguments configuration field allows you to map the field name in the type to the argument name expected by the query.

For example, the author query below expects an id as its argument, but the author's ID within the Book fields is authorID. You can use arguments to map the queries argument name (i.e. id) to the field name on the type (i.e. authorID).

type Book {
  id: ID!
  name: String!
  originalPublishingDate: Date!
  authorID: ID!
  author: Author
  @materializer(
    query: "author"
    arguments: [{ name: "id" field: "authorID"}]
  )
}

arguments allows you to specify an array containing multiple name/field mappings:

arguments: [
  { name: "argument1" field: "field1"}
  { name: "argument2" field: "field2"}
  ]

Handling Nested JSON Results

When calling a REST API, often the results come back as nested objects. We can use setters to map these to a flat result (see our docs for @rest for more details), but in many cases you may want to map the nested objects to separate GraphQL types. This can be done via @materializer.

For example, let's say I was calling the random user API. A partial JSON result looks like the following:

{
  "gender": "male",
  "name": {
      "first": "Brecht",
      "last": "Polfliet"
  },
  "location": {
      "city": "Ter Apelkanaal",
      "state": "Utrecht",
      "country": "Netherlands",
  },
  "email": "brecht.polfliet@example.com"
}

We can use setters to map the name fields to the main randomUser type, but we want to assign the results under location to a Location object. We would use @materializer to fulfill the data, returning a Location type as follows:

type RandomUser {
  gender: String!
  firstName: String!
  lastName: String!
  email: String!
  location: Location @materializer(query: "userLocation")
}

type Location {
  city: String!
  state: String!
  country: String!
}

type Query {
  randomUser: RandomUser
    @rest(
      endpoint: "https://randomuser.me/api"
      resultroot: "results[]"
      setters: [
        { field: "firstName", path: "name.first" }
        { field: "lastName", path: "name.last" }
      ]
    )
  userLocation: Location
    @rest(
      endpoint: "https://randomuser.me/api"
      resultroot: "results[].location"
    )
}

Note that the root (i.e resultroot) for location is the nested structure for results[].location.

But would this result in two different API calls? No. If the first URL and the second one match exactly, then the second query will hit the cache and not be made. There are other factors that can affect this, but the goal is to offer the benefits of independence with the efficiency where possible.

This site uses cookies: By using this website, you consent to our use of cookies in accordance with our Website Terms of Use and Cookie Policy.