Technical

From GraphQL APIs to Supergraph Using Gloo Gateway Schema Stitching

In today’s business world, companies often have different teams or lines of business that necessitate multiple GraphQL APIs tailored to their needs. This approach helps teams work efficiently and deliver better user experiences, but there are instances where these schemas need to be merged into a unified API, enabling teams to access data from various sources through a single endpoint.

In the following tutorial we will discuss how we can merge multiple graphQL APIs with Gloo Gateway using GraphQL schema stitching.

What Is GraphQL Schema Stitching

GraphQL schema stitching is a technique in GraphQL that enables the merging of multiple schemas to create a unified supergraph. For instance, a company with an existing GraphQL API can use this method to enhance its current API by integrating it with a new GraphQL API developed using Gloo Gateway.

Real-World Example

Prerequisites

This tutorial uses Gloo Gateway Enterprise with GraphQL capabilities. If you need a trial key, reach out to us here.

Install Gloo Gateway Enterprise on your cluster using the following helm chart:

helm repo add glooe https://storage.googleapis.com/gloo-ee-helm

helm install gloo glooe/gloo-ee --namespace gloo-system --create-namespace --set-string license_key=$LICENSE

Assuming we have the following blog application, it consists of two microservices, one storing blogs and one storing the comments related to the blogs.

You can deploy these two services locally using the following command:

# Blogs 
kubectl apply -f https://raw.githubusercontent.com/asayah/gloo-gateway-graphql-stitching-blog/main/svcs/blogs.yaml

# Comments
kubectl apply -f https://raw.githubusercontent.com/asayah/gloo-gateway-graphql-stitching-blog/main/svcs/comments.yaml

We can now use Gloo Gateway to create a GraphQL API that will aggregate the results of the two microservices. Let’s call the new GraphQL API the content API – it will return blogs and their related comments, and the usernames of the authors.

To do this in Gloo Gateway we will create some configuration. To start, we will create the GraphQL schema, which contains the resolvers:

kubectl apply -f https://raw.githubusercontent.com/asayah/gloo-gateway-graphql-stitching-blog/main/rest-resolvers/graphqlapi.yaml

This is the configuration we applied:

apiVersion: graphql.gloo.solo.io/v1beta1
kind: GraphQLApi
metadata:
  name: blogs-graphql
  namespace: gloo-system
spec:
  options:
    logSensitiveInfo: true
  executableSchema:
    executor:
      local:
        enableIntrospection: true
        resolutions:
          getBlogs:
            restResolver:
              request:
                headers:
                  :method: GET
                  :path: /blogs
              upstreamRef:
                name: default-blogs-80
                namespace: gloo-system
          getComments:
            restResolver:
              request:
                headers:
                  :method: GET
                  :path: /comments?blogid={$parent.id}
              upstreamRef:
                name: default-comments-80
                namespace: gloo-system

    schemaDefinition: |
      type Query {
        """Description of a blogs in HTML"""
        getBlogs: [Blog] @resolve(name: "getBlogs")
      }

      type Blog {      
        id: Int
        user: User
        content: String
        title: String
        comments: [Comment] @resolve(name: "getComments")
      }

      type Comment {      
        id: Int
        user: User
        comment: String
      }

      type User {      
        username: String
      }

Let’s understand the configuration above – we create a GraphQLApi custom resource in our Kubernetes cluster. The GraphQLApi contains two resolvers, getBlogs and getComments, getBlogs gets the blogs from the blogs service, getComments is then invoked to get all the comments related to a blog passing the blogId in a query parameter.

Now, to expose the GraphQL API to the public using the virtual service, create the following configuration:

kubectl apply -f https://raw.githubusercontent.com/asayah/gloo-gateway-graphql-stitching-blog/main/rest-resolvers/vs.yaml

Here is the configuration we applied:

apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: default
  namespace: gloo-system
spec:
  virtualHost:
    domains:
    - '*'
    options:
      cors:
        allowCredentials: true
        allowHeaders:
        - content-type
        allowMethods:
        - POST
        allowOriginRegex:
        - '/*'
    routes:
      # ----------- Route to the Declared GraphQL API -----------
    - graphqlApiRef:
        name: blogs-graphql
        namespace: gloo-system
      matchers:
      - prefix: /graphql

Now your GraphQL API is exposed, and you can send your requests. For example, let’s retrieve the blogs and their related comments using the following query:

 query MyQuery {
   getBlogs {
     comments {
       comment
       id
       user {
         username
       }
     }
     content
     id
     title
     user {
       username
     }
   }
 }

You should get a result like this:

{
 "data": {
   "getBlogs": [
     {
       "id": 1,
       "title": "Proin eu mi",
       "content": "Proin eu mi. Nulla ac enim. In tempor...",
       "user": {
         "username": "dbosnell2"
       },
       "comments": [
         {
           "id": 1,
           "comment": "Fusce consequat. Nulla nisl. Nunc nisl...",
           "user": {
             "username": "cguillot21"
           }
         },
         {
           "id": 13,
           "comment": "Vestibulum ac est lacinia nisi venenatis...",
           "user": {
             "username": "ballonby2a"
           }
         },
         {
           "id": 16,
           "comment": "In sagittis dui vel nisl....",
           "user": {
             "username": "baguilar27"
           }
         }
       ]
     }
   ]
 }
}

This result can be used now to build an UI, for example, that lists new blogs and their related content. However, what if I want to display more information regarding the authors (of the blogs and comments), but I only have the usernames? Fortunately, in this example, there is another team that owns user data, and they have an existing GraphQL API that we can leverage to get more info regarding the authors.

Let’s deploy the Users service:

# Users 
kubectl apply -f https://raw.githubusercontent.com/asayah/gloo-gateway-graphql-stitching-blog/main/svcs/users.yaml

GraphQL Schema Stitching Using Gloo Gateway

Using schema stitching, it is possible to enhance the existing data from the GraphQL API created previously with user info fetched from an existing GraphQL API. The userInfo GraphQL API in this example is using an Apollo GraphQL server, but this GraphQL API can be served by any GraphQL server, it can also be another Gloo Gateway instance like in a tiered Gateway Deployment.

Now it is possible to retrieve the first and last name of a user using their username. This is possible because of the GraphQL schema stitching:

To stitch the two schemas we are going to do two things: first we will create a GraphQLApi that represents the User GraphQL API. In this case we want a remote execution of the graphQL API (proxied to the Apollo GraphQL server) and then we will create an GraphQLApi that represents the schema stitching.

Apply the following configuration to represent the proxied User GraphQL API:

kubectl apply -f https://raw.githubusercontent.com/asayah/gloo-gateway-graphql-stitching-blog/main/remote-execution/graphqlapi.yaml

Here is the configuration we applied:

apiVersion: graphql.gloo.solo.io/v1beta1
kind: GraphQLApi
metadata:
  name: remote-graphql-users
  namespace: gloo-system
spec:
  options:
     logSensitiveInfo: true
  executableSchema:
    executor:
      remote:
        upstreamRef:
          name: default-users-80
          namespace: gloo-system
    schemaDefinition: |
      type User {
        id: Int!
        username: String
        lastname: String
        firstname: String
      }

      type Query {
        getUserDetails(username: String!): User
      }
EOF

This GraphQL API is proxying the query getUserDetails to upstream default-users-80, which is the Apollo GraphQL server.

Now we can create the stitched schema using the following configuration:

kubectl apply -f https://raw.githubusercontent.com/asayah/gloo-gateway-graphql-stitching-blog/main/stitching/graphqlapi.yaml

Here is the configuration we applied:

apiVersion: graphql.gloo.solo.io/v1beta1
kind: GraphQLApi
metadata:
  name: stitched-gql
  namespace: gloo-system
spec:
  options:
     logSensitiveInfo: true
  stitchedSchema:
    subschemas:
    - name: remote-graphql-users
      namespace: gloo-system
      typeMerge:
        User:
          # The selectionSet declares that the username from the Blogs service will be used as the key
          # to fetch the user details from the Users service.
          selectionSet: '{ username }'
          queryName: getUserDetails
          args:
            username: username
    - name: blogs-graphql
      namespace: gloo-system

It is important to note that in the stitched GraphQL API we defined a typeMerge for the type User; this will invoke the query getUserDetails based on a username during the merge.

Finally, expose this new stitched GraphQL schema using a virtual Service; we will just update the existing one:

kubectl apply -f https://raw.githubusercontent.com/asayah/gloo-gateway-graphql-stitching-blog/main/stitching/vs.yaml

Here is the configuration:

apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: default
  namespace: gloo-system
spec:
  virtualHost:
    domains:
    - '*'
    options:
      cors:
        allowCredentials: true
        allowHeaders:
        - content-type
        allowMethods:
        - POST
        allowOriginRegex:
        - '/*'
    routes:
      # ----------- Route to the Stitched GraphQL API -----------
    - graphqlApiRef:
        name: stitched-gql
        namespace: gloo-system
      matchers:
      - prefix: /graphql

You can try the stitched GraphQL API now making the following query:

query MyQuery {
   getBlogs {
     comments {
       comment
       id
       user {
         username
         firstname
         lastname
       }
     }
     content
     id
     title
     user {
       username
       firstname
       lastname
     }
   }
 }

You should get the following response:

{
        "comments": [
          {
            "comment": "Fusce consequat. Nulla nisl. Nunc nisl.\n\nDuis bibendum, felis sed interdum venenatis, turpis enim blandit mi, in porttitor pede justo eu massa. Donec dapibus. Duis at velit eu est congue elementum.",
            "id": 1,
            "user": {
              "username": "cguillot21",
              "firstname": "Correy",
              "lastname": "Guillot"
            }
          },
          {
            "comment": "Vestibulum ac ....",
            "id": 13,
            "user": {
              "username": "ballonby2a",
              "firstname": "Bendite",
              "lastname": "Allonby"
            }
          },
          {
            "comment": "In sagittis dui vel nisl. Duis ac nibh. Fusce lacus purus, aliquet at, feugiat non, pretium quis, lectus.",
            "id": 16,
            "user": {
              "username": "baguilar27",
              "firstname": "Braden",
              "lastname": "Aguilar"
            }
          }
        ],
        "content": "Proin eu mi. Nulla ac enim. In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem.",
        "id": 1,
        "title": "Proin eu mi",
        "user": {
          "username": "dbosnell2",
          "firstname": "Dalia",
          "lastname": "Bosnell"
        }
      },

Now we see that we get the first and last name of each author, and this was possible because of GraphQL schema stitching.

Use Gloo Gateway for GraphQL Stitching

In this blog, we looked at how GraphQL Schema Stitching can combine two GraphQL APIs using Gloo Gateway. One API was built with Gloo Gateway, and the other with Apollo, merging them seamlessly. This merging creates a “supergraph,” allowing access to data from different parts of an organization.

Gloo Gateway not only creates GraphQL APIs but also secures and monitors them with advanced gateway features. To see how GraphQL Schema Stitching can benefit your setup, request a Gloo Gateway trial key today.