How to Eliminate Duplicated Requests with GraphQL
Tags: graphql, discuss, productivity
Published: 2022-04-26 18:51:52

According to graphql.org’s [docs](https://graphql.org/learn/schema/#interfaces), “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.](https://github.com/carloseberhardt/sz-interface-filter)

Let’s say you’re making requests to two example services, [postman-echo](https://www.postman.com/postman/workspace/published-postman-templates/documentation/631643-f695cab7-6878-eb55-7943-ad88e1ccfd65?ctx=documentation) and [httpbin](https://httpbin.org/). You want to return JSON data for three fields

```graphql

  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:

```graphql
.
├── 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](https://stepzen.com/docs/design-a-graphql-schema/custom-graphql-directives#@sdl)):

```graphql
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:

```graphql
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` :

```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](https://stepzen.com/docs/connecting-backends/how-to-connect-a-rest-service) 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 https://username.stepzen.net/api/intentional-stingray/__graphql) to StepZen in a few seconds. We’ll also be able to explore the endpoint deployed to our localhost with GraphiQL.

```bash
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt6ak175fv2xc57apiij.png)
![Screenshot of Postman response](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5vgg5d1mrngm1xx7jqlx.png)
  

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](https://discord.com/invite/9k2VdPn2FR). We'd love to see you around!

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

- [Getting Started](/docs/getting-started)
- [Connecting Backends](/docs/connecting-backends)
- [Design A GraphQL Schema](/docs/design-a-graphql-schema)
- [The StepZen CLI](/docs/cli)