Union types are a way to define a field that can return one of a list of types. For example, when you're building a GraphQL API that has a query to search for publications. These publications can be books, magazines, or other types of publications. But what if every publication type has a different set of fields?

This blog post will look at how to use union types in GraphQL to make your schema more flexible. We'll also look at how to use union types in StepZen, a GraphQL API solution that allows you to query multiple APIs with a single GraphQL endpoint.

Using Union Types in a GraphQL schema

With union types, you can make your schema more flexible. Let's look at the following schema, where we have a SearchResult type that can return either a Book or a Magazine type:

type Book {
  title: String!
  authors: [String]!
}

type Magazine {
  title: String!
}

union SearchResult = Book | Magazine

In this example, the SearchResult type can return either a Book or a Magazine type. This is useful when we want to return a list of publications that can be either a book or a magazine. Especially as the Book type has an authors field, but the Magazine type doesn't.

The query that resolved to the SearchResult type can be defined as follows:

type Query {
  search(query: String!): [SearchResult]!
}

If we didn't use a union type, we would need to define a separate query for each publication type, resulting in a lot of duplication in our schema.

Querying Union Types

When you send a request to the GraphQL endpoint, you need to define which fields you want to be returned in case the response is of either type you want to query. GraphQL uses inline fragments to specify which fields you want to query for each type.

For example, if we want to query the title and authors fields of a Book and only the title field of a Magazine, we can define the query as follows:

query search {
  search(query: "webdevelopment") {
    ... on Book {
      title
      authors
    }
    ... on Magazine {
      title
    }
  }
}

The GraphQL server will return a list of publications that match the search term "webdevelopment". If the publication is a book, the server will return the title and authors fields. The server will return the title field if the publication is a magazine.

Using Union Types in StepZen

When you're building a GraphQL API with StepZen, you can, of course, also use union types. Let's create a new StepZen endpoint that will query the Google Books API. The Google Books API is a public API that allows us to search books and magazines.

Create a StepZen endpoint

To create a new StepZen endpoint, we need to install the StepZen CLI. The StepZen CLI is a command line tool that allows us to create, deploy, and manage StepZen endpoints.

To install the StepZen CLI, we can run:

npm install -g stepzen

After installing the StepZen CLI, we can create a new directory for our project. In this directory, we can initiate a new StepZen project by running the following:

stepzen init --endpoint=api/googlebooks

The CLI will create a new file called stepzen.config.json, which contains the configuration for our project, such as the endpoint name.

Next, we need to create a schema file. This file will contain the schema for the Google Books API. We can generate this schema file by running the following:

stepzen import curl 'https://www.googleapis.com/books/v1/volumes?q=webdevelopment&printType=magazines&country=US' --name=googlebooks --query-name=search --query-type=SearchResults

The generated schema is a valid GraphQL schema describing the data we can query from the Google Books API. The schema includes a query called search that returns a list of publications based on a search term (q). Also, you can filter by country (country) and the type of publication (printType). The printType argument can be either books or magazines.

To deploy the schema as a StepZen endpoint, we can run:

stepzen start

This will deploy the schema to StepZen and return the endpoint it's available on in your terminal. Also, you get a link to explore the endpoint in the StepZen dashboard, as you can see in the next step.

Explore the Google Books API

We can explore the API by visiting the Explorer in the StepZen dashboard at https://dashboard.stepzen.com/explorer. The Explorer allows us to explore the GraphQL API by sending requests and viewing the schema.

Query the Google Books API from the StepZen Dashboard

Let's try sending a request to get the response for the search query, which returns a list of books and magazines. We can send a request by clicking the "Run" button, and the Explorer will send a request to the StepZen endpoint and display the results.

query search {
  search(
    country: "US",
    printType: "magazines",
    q: "webdevelopment"
  ) {
    items {
      volumeInfo {
        title
        publishedDate
      }
    }
  }
}

This query returns a list of magazines that match the search term "webdevelopment". Instead of finding a list of magazines, we can use the same Google Books API endpoint to retrieve a list of books. This is because the search query allows us to change the argument printType to books to retrieve a list of books. By looking at the Google Books documentation, we can see that when the printType argument is books we can retrieve additional fields such as authors and industryIdentifiers -- which contain the ISBN of the book.

However, when we run the query with the printType argument set to books and request these additional fields, we get an error:

Missing types for the Google Books API

The Google Books API returns different data for magazines than for books, so we can't query the same fields for both types. To fix this, we can use a union type to define which fields are available for each type.

Generate a schema with a union type

Before we can add the union type, we need to generate a new schema file that includes the response types for books. We can do this by running:

stepzen import curl 'https://www.googleapis.com/books/v1/volumes?q=webdevelopment&printType=books&country=US' --name=books_googlebooks --query-name=searchbooks --query-type=SearchResults --prefix=Books

The Books prefix is used to avoid naming conflicts with other types in the GraphQLschema, as there is a huge overlap between the types for books and magazines.

With this new query and schema, we can query the searchbooks query to get a list of publications, where the type BooksVolumeInfo is used for the volumeInfo field. This type contains the fields title, authors, and industryIdentifiers.

To set up the union type, we need to alter the schema file that includes the search query. We can do this by opening the googlebooks/index.graphql file and adding the following code to it:

type MagazinesVolumeInfo {
  allowAnonLogging: Boolean
  canonicalVolumeLink: String
  contentVersion: String
  description: String
  imageLinks: ImageLinks
  infoLink: String
  language: String
  maturityRating: String
  pageCount: Int
  panelizationSummary: PanelizationSummary
  previewLink: String
  printType: String
  publishedDate: Date
  readingModes: ReadingModes
  title: String
}

union VolumeInfo = MagazinesVolumeInfo | BooksVolumeInfo

In the above, we've renamed the VolumeInfo type to MagazinesVolumeInfo and created a new union type called VolumeInfo. The union type contains the MagazinesVolumeInfo type and the BooksVolumeInfo type from the schema file that includes the searchbooks query.

Explicitly define the type names for the union type

In a previous step, we've seen that the Google Books API returns different data for books and magazines. This means that the search query can return a list of publications that are either books or magazines. As they return different fields, the union type VolumeInfo resolves to either MagazinesVolumeInfo or BooksVolumeInfo.

Often, StepZen can determine which member of the union type the data belongs to based on the returned data. However, in this case, there are a few common fields between the two types. This means that StepZen can't easily determine the union type member based on the returned data.

This means that we need to explicitly set the __typename field to determine the publication type for each item in the list.

To do this, we need to add the __typename field to the search query. We can do this by opening the googlebooks/index.graphql file and editing the search query to look like this:

type Query {
  search(country: String, printType: String, q: String): SearchResults
    @rest(
      endpoint: "https://www.googleapis.com/books/v1/volumes"
      ecmascript: """
       function transformREST(s) {
        let out = JSON.parse(s);
        out.items = out.items.map((item) => {
          let volumeInfo = item.volumeInfo;

          volumeInfo.__typename = volumeInfo.printType === 'BOOK' ? 'BooksVolumeInfo' : 'MagazinesVolumeInfo';

          return {
            volumeInfo: volumeInfo
          }
        })
        return JSON.stringify(out);
      }
      """
    )
}

To set the __typename field, we use the ecmascript directive to run some JavaScript code. In the code, we check the value of the printType field and set the __typename field to either BooksVolumeInfo or MagazinesVolumeInfo.

Query the Google Books API with a union type

Now that we've set up the union type, we can retrieve magazines and books from the Google Books API using the search query.

From the StepZen dashboard, we can send a request with the following query:

query search {
  search(
    country: "US",
    printType: "all",
    q: "webdevelopment"
  ) {
    items {
      volumeInfo {
        __typename
        ...on BooksVolumeInfo {
          title
          authors
          industryIdentifiers {
            type
            identifier
          }
        }
        ...on MagazinesVolumeInfo {
          title
        }
      }
    }
  }
}

Which results in the following response:

Querying the Google Books API with a union type

This query returns a list of magazines and books that match the search term "webdevelopment". The __typename field is used to determine the publication type. If the type is BookVolumeInfo, we can query the fields title, authors, and industryIdentifiers. If the type is MagazineVolumeInfo, we can query the field title.

Conclusion

In this tutorial, we've learned about using union types in a GraphQL schema and how to use them in a request. We've also seen how to use StepZen to create a GraphQL API for the Google Books API by using the StepZen CLI to generate a schema file and the StepZen Explorer to send requests. Finally, we've seen how to use a union type to query the Google Books API for both books and magazines.

Want to learn more about StepZen? Try it out here or ask any question on the Discord here.