Create a Remote Schema to wrap a REST API with Hasura

What is a Remote Schema

A remote schema is simply an external GraphQL service that you can stitch with Hasura GraphQL Engine for a unified GraphQL API. A common way to incrementally adopt GraphQL in an existing infrastructure, is to wrap pre-existing REST APIs within a GraphQL layer. In this blogpost, we will see how you can do this using Hasura easily.

Example REST API

Suppose, you have a REST API like the following:

GET /users
GET /users/:userId
POST /users

The GET /users   endpoint also takes an optional query param i.e. GET /users?name=abc and the POST /users endpoint expects a valid JSON payload in the body.

Let's see how we can wrap this in GraphQL.

Bootstrap a GraphQL Service

We can start by picking up a minimal boilerplate for a GraphQL server, say this: https://github.com/hasura/sample-remote-schema (or jump to final implementation here)

This boilerplate is built using the Apollo Server framework. It is simply a hello schema i.e. on query { hello } it returns  { data": {"hello": "world"} }

const typeDefs = gql`
  type Query {
    hello:  String
  }`;

const resolvers = {
    Query: {
        hello: () => "world",
    },
};

Build the Schema, Fill in the Types

For our REST API (from above), lets start defining some new types and fields. The complete definition of types and fields is what makes our schema :

const typeDefs = gql`
  type User {
    id:       String!
    name:     String!
    balance:  Int!
  }

  type Query {
    getUser(id: String!): User
    users(name: String): [User]
  }

  type Mutation {
    addUser(name: String!, balance: Int!): User
  }
`;

Roughly our REST to GraphQL mapping looks like the following:

REST GraphQL
GET /users users (name: String) : [User]
GET /users/:userId getUser(id: String!): User
POST /users addUser(name: String!, balance: Int!): User

We can already notice some extra information about the APIs and this is one of the selling points of GraphQL: we can see input and output type information very clearly. Lets now move to implementing the APIs.

Resolve!

In a REST world, we usually talk about writing handlers for endpoints. In GraphQL, we do a similar thing but call it resolvers!

For the schema that we defined in the previous section, lets add their corresponding resolvers:

const resolvers = {
    Query: {
        getUser: async (_, { id }) => {
            return await getData(MY_REST_URL + '/users/' + id);
        },

        users: async (_, { name }) => {
            var nameParams = '';
            if (name) {
                nameParams = '?name=' + name;
            }
            return await getData(MY_REST_URL + '/users' + nameParams);
        }
    },

    Mutation: {
        addUser: async (_, { name, balance } ) => {
           return await postData(MY_REST_URL + 'users', { name, balance } );
        }
    }
};

Easy! All we did was proxy the incoming GraphQL request to our REST API.

Finally, we need to deploy this service somewhere and get a URL. There are plenty of cloud solutions that allow you to deploy a Node service easily. You can look at the final implementation with deployment instructions on Heroku here.

Add to Hasura

Once you have gotten an HTTP URL for your above GraphQL service, just head over to your Hasura console and add it as a Remote Schema. In case your remote schema defines few types that are same as Hasura, they will get merged automatically too. Notice that you can also add Authorization and other headers to your Remote Schema in case your REST API expects such headers.

Add a Remote Schema through Hasura Console

Now, you should be able to call your remote schema APIs alongwith the default Hasura APIs from the Hasura GraphQL Endpoint. And that's it!

Querying Remote Schema from Hasura console

Conclusion

It is easy to wrap your existing REST API into a GraphQL API. The advantages of these are many:

1) you can incrementally adopt GraphQL in your existing infrastructure,

2) you get added benefits over REST APIs like type safety and more readability,

3) you get a unified API layer for all your APIs.

With the guide presented above, you can get started with your GraphQL wrapped REST API in minutes. You can then add this GraphQL service as a Remote Schema in Hasura for automatic schema-stitching.


Hasura is an open-source engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.