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