Write custom resolvers
Now we saw how the GraphQL API can be extended using Actions. We mentioned earlier that another way of customizing the API graph is through a custom GraphQL server.
Let's take the same use-case of fetching profile information from Auth0.
Hasura can merge remote GraphQL schemas and provide a unified GraphQL API. To handle the use-case of fetching Auth0 profile information, we will write custom resolvers in a custom GraphQL server. Hasura can then merge this custom GraphQL server with the existing auto-generated schema.
This custom GraphQL server is the Remote Schema
.
Write GraphQL custom resolver
So let's write a custom resolver which can be later merged into Hasura's GraphQL API.
const { ApolloServer } = require('apollo-server');const gql = require('graphql-tag');const jwt = require('jsonwebtoken');const fetch = require('node-fetch');const typeDefs = gql`type auth0_profile {email: Stringpicture: String}type Query {auth0: auth0_profile}`;function getProfileInfo(user_id) {const headers = {Authorization: `Bearer ${process.env.AUTH0_MANAGEMENT_API_TOKEN}`,};console.log(headers);return fetch(`https://${process.env.AUTH0_DOMAIN}/api/v2/users/${user_id}`, {headers,});}const resolvers = {Query: {auth0: (parent, args, context) => {// read the authorization header sent from the clientconst authHeaders = context.headers.authorization || '';const token = authHeaders.replace('Bearer ', '');// decode the token to find the user_idtry {if (!token) {return 'Authorization token is missing!';}const decoded = jwt.decode(token);const user_id = decoded.sub;// make a rest api call to auth0return getProfileInfo(user_id).then((resp) => resp.json()).then((resp) => {console.log(resp);if (!resp) {return null;}return { email: resp.email, picture: resp.picture };});} catch (e) {console.log(e);return null;}},},};const context = ({ req }) => {return { headers: req.headers };};const schema = new ApolloServer({ typeDefs, resolvers, context });schema.listen({ port: process.env.PORT }).then(({ url }) => {console.log(`schema ready at ${url}`);});
In the server above, let's breakdown what's happening:
- We define the GraphQL types for
auth0_profile
andQuery
. - And then we write a custom resolver for Query type
auth0
, where we parse theAuthorization
headers to get the token. - We then decode the token using the
jsonwebtoken
library'sjwt
method. This gives the user_id required to fetch auth0 profile information. - We request the Auth0's Management API, passing in the token and the user_id to get details about this user.
- Once we get a response, we return the object
{email: resp.email, picture: resp.picture}
as a response. Else, we returnnull
.
Note
Most of the code written is very similar to the REST API code we wrote in the previous section for Actions. Here we are using Apollo Server to write a custom GraphQL server from scratch.
If you have created auth0
Action from Creating Actions
part, then Action will collide with auth0 Remote schema. To solve this you can remove Action to be able to create Remote schema or rename auth0
and auth0_profile
types.
Deploy
Let's deploy the above custom GraphQL server to Glitch. Glitch is a platform to build and deploy apps (Node.js) and is a quick way to test and iterate code on the cloud. Click on the Deploy to Glitch button below to get started.
Environment variables
After remixing to your own project on Glitch, modify the .env
file to enter the
AUTH0_MANAGEMENT_API_TOKEN
AUTH0_DOMAIN
values appropriately.
Congrats! You have written and deployed your first GraphQL custom resolver.
- Build apps and APIs 10x faster
- Built-in authorization and caching
- 8x more performant than hand-rolled APIs