(Editor's Note: In his last post, freelance developer Joey Anuff showed how easy it is to combine Spotify and Google data using StepZen's @materializer
directive. We welcome him back to explain how StepZen's @sequence
directive simplifies adding OAuth authorization to that request. For the full code, visit Joey's GitHub repo at januff/stepzen-spotify-knowledge.)
When I used StepZen to sync the Spotify and Knowledge Graph APIs, I quickly encountered a common headache with mixed APIs: mixed authorization requirements. Specifically, requests to Google's Knowledge Graph require an API key that never expires, while requests to Spotify require an access token that expires after just an hour.
Hand-cranking a temporary token using the Spotify web dashboard was good enough for a quick demo, but given the simplicity of our OAuth request–which involves no user authentication, only application authentication–we were left with a perfect case study to illustrate StepZen's handling of the most basic of OAuth flows: the Client Credentials Flow.
StepZen's @sequence
directive, our tool for this task, is complementary to their @materializer
directive–the former for extending query definitions, the latter for extending type definitions–and can be seen as different means to the same end: ordering your API calls.
Where @materializer
allows us to step through our API requests in implicit order, simply by descending through our type fields and back-filling secondary data, @sequence
lets us step through API requests in explicit order. Also different: unlike the @materializer
directive, which we nest inside our type definitions, we locate the @sequence
directive inside a query definition, a better home for transitory permissions data incidental to our Spotify_Track
type.
Here's how, using @sequence
, we loop an Auth call into our Spotify track search in just three steps (a simplified version of Sam Hill's recent Auth 2.0 walkthrough.)
1. Add Spotify Auth type and query to our Spotify GraphQL
Spotify's authorization endpoint behaves the same as the HubSpot server in Sam's example, but our grant_type
of client_credentials
returns an even simpler JSON response, of which access_token
is the only field we'll be preserving.
Translating this exchange into StepZen-enhanced GraphQL is as simple as defining a Spotify_Auth
type and an @rest
-powered query to return it, like so:
type Spotify_Auth {
access_token: String!
}
type Query {
get_auth: Spotify_Auth
@rest(
method: POST
contenttype: "application/x-www-form-urlencoded"
endpoint: "https://accounts.spotify.com/api/token?grant_type=client_credentials&client_id=$client_id&client_secret=$client_secret"
configuration: "spotify_config"
)
}
2. Add an authorization step to a new @sequence
-driven query: spotify_Search_With_Token
In a @sequence
of steps, all fields returned from a prior step are automatically supplied as parameters to the next query, but prior fields or initial arguments need to be included, as with the initial q
parameter in the spotify_Search
step below.
type Query {
spotify_Search_With_Token(
q: String!
): Spotify_Track
@sequence(
steps: [
{ query: "get_auth" }
{ query: "spotify_Search"
arguments: [
{ name: "q", argument: "q" }
]
}
]
)
}
3. Add access_token
as required argument to our existing spotify_Search
query
Finally, we add access_token
as a required argument to the spotify_Search
query–instead of passing in the hand-coded value from our config, as I did in my first pass. It's still available as $access_token
, but now it's a dynamic value, supplied by the @sequence
-prepended get_auth
query from Step One.
type Query {
"""
Get Spotify Catalog information about artists that match a keyword string.
"""
spotify_Search(
"""
Query keywords and optional filters and operators. E.g., `jazz pop`
"""
q: String
limit: Int = 1
access_token: String!
): [Spotify_Track]
@rest(
endpoint: "https://api.spotify.com/v1/search?q=$q&type=track"
headers: [{ name: "Authorization", value: "Bearer $access_token" }]
(...)
And that's it! Now we can explore our data at leisure, unconcerned with dying tokens.
As we evolve our query to modify user data–expanding our grant_type
and adding redirect URLs to our OAuth flow–we'll be adding new queries and steps, but we'll largely be relying on these same @materializer
and @sequence
directives to make them work.