How to Eliminate Duplicated Requests with GraphQL

How to Eliminate Duplicated Requests with GraphQL

·

5 min read

According to graphql.org’s docs, “An Interface is an abstract type that includes a certain set of fields that a type must include to implement the interface.” When you’re weaving APIs into your GraphQL layer, you may conclude that you need to use interface queries, if, for example, you wanted to define more than one data source to hydrate a given type. You can then use the parameter of the query to execute it on the condition that it matches the chosen parameter, using StepZen's custom @supplies directive that can execute interface queries based on its arguments (we'll go into more detail soon).

There are a couple of reasons you might want to conditionally execute interface queries. The first is that if the requests are to your own API rather than a third-party service, you’d want to avoid 404 errors or extra requests. But if the requests are to a third-party service, you might want to use interface queries anyway, if you have rate limits or quotas to think about. This might seem a little opaque without an example, so let’s dive in to learn how to eliminate duplicated requests.

The Example: Switch Between Two Sources to Get JSON Data

Note: You can fork and clone all the code from this example at this repository.

Let’s say you’re making requests to two example services, postman-echo and httpbin. You want to return JSON data for three fields


  args: JSON
  headers: JSON
  url: String

You would like to have a single query, with a provider parameter that returns the JSON data associated with each type depending on whether that provider is Httpbin or Postman (because, while these are example services, let’s pretend that Httpbin will charge extra for calls over your monthly limit, so you don’t want to make a call to Httpbin every time you make a call to Postman ).

Let’s zoom out for a moment and take a look at the StepZen project structure:

.
├── httpbin/
│   └── index.graphql
├── postman/
│   └── index.graphql
├── echo.graphql
└── index.graphql

In this structure,

httpbin/index.graphql defines the schema that connects to httpbin.

postman/index.graphql is the schema that connects to Postman.

your-working-directory/index.graphql is a file that marshals the schemas for StepZen’s service via a custom @sdl directive like so. @sdl allows you to specify all the GraphQL files you want to assemble into your unified GraphQL schema. (Learn more about @sdl in our docs):

schema
  @sdl(
    files: ["postman/index.graphql", "httpbin/index.graphql", "echo.graphql"]
  ) {
  query: Query
}

And your-working-directory/echo.graphql itself links types from postman/ and httpbin/ together via an interface:

interface Echo {
  args: JSON
  headers: JSON
  url: String
}

type utility {
  provider: String
}

type Query {
  echo(provider: String!): Echo
}

This interface includes the three data fields you’d like to return from each API. The echo Query implements the provider parameter to return data from the service depending on whether ‘httpbin’ or ‘postman’ is specified.

But how does it do this? Let’s take a closer look at one of the schemas, postman/index.graphql :

type Postman implements Echo {
  args: JSON
  headers: JSON
  url: String
}

type Query {
  postman: Postman @rest(endpoint: "https://postman-echo.com/get")

  postmanIQ(provider: String!): Postman
    @supplies(query: "echo")
    @sequence(steps: [{ query: "filterPostman" }, { query: "postman" }])

  filterPostman(provider: String!): [utility]
    @rest(
      endpoint: "stepzen:empty"
      cel: """
      function transformREST(s) {
        let p = get("provider")
        if (p === "postman") {
          return JSON.stringify({provider: "postman"})
        } else {
          return ""
        }
      }
      """
    )
}

We’ll break down what’s happening line-by-line.

First, type Postman implements the Echo interface. Next, the postman query uses StepZen’s custom @rest directive to connect to the Postman API. The postmanIQ query uses two more StepZen directives: @supplies and @sequence.

@supplies connects a query on a concrete type to an interface query, so it connects Postman to Echo .

@sequence calls each specified step in a sequence, using the type returned from one step as the parameter in the next. So, filterPostman returns a utility type that is used as a parameter to call the first postman query.

Lastly, you can see that filterPostman implements custom logic in the @rest directive to make the call if the provider matches “postman”.

The logic inside httpbin/index.graphql is much the same.

The Solution: Use the Same Query to Retrieve Data From Either Source

If you’ve cloned down the example project, you can run stepzen start inside it and deploy the GraphQL endpoint (here it’s named username.stepzen.net/api/intentional-stingr..) to StepZen in a few seconds. We’ll also be able to explore the endpoint deployed to our localhost with GraphiQL.

Deploying api/intentional-stingray to StepZen... done in 6.2s 🚀

Your API url is  https://username.stepzen.net/api/intentional-stingray/__graphql

You can test your hosted API with cURL:

curl https://username.stepzen.net/api/intentional-stingray/__graphql \
   --header "Authorization: Apikey $(stepzen whoami --apikey)" \
   --header "Content-Type: application/json" \
   --data '{"query": "your graphql query"}'

or explore it with GraphiQL at  http://localhost:5001/api/intentional-stingray

Watching ~/sz-interface-filter for GraphQL changes...

If you check out the GraphiQL Explorer at http://localhost:5001/api/intentional-stingray, you can see how the query in Echo works:

Screenshot of httpbin response Screenshot of Postman response

You can use the same query to retrieve data either from httpbin or Postman, depending on which one you need! This eliminates duplicated requests without having to repeat the same GraphQL query logic with slightly different parameters.

Where to Go From Here

If you have questions, feel free to slide into our Discord. We'd love to see you around!

To learn more about creating GraphQL APIs quickly with StepZen, see