kriasoft/graphql-starter-kit

Data from External ReST API

go4cas opened this issue · 1 comments

From the README, it seems fairly straightforward to implement connections to multiple data stores. How would I go about it, if one (or more) of my data sources were not direct access to the DB, but through an external ReST API?

Let's say you want to use GitHub's REST API for exposing Gists via your GraphQL API.

For that, you start by creating GistType.js that lists all the fields that you want to expose to your API users. See schema/StoryType.js, schema/CommentType.js as an example.

Then you can add a "data loader" that will fetch a Gist from GitHub by it's ID, you can add it to src/Context.js:

gistById = new DataLoader(ids =>
  ids.map(id =>
    fetch(`https://api.github.com/gists/${id}`, {/* options */}).then(x => x.json())
);

Then update GraphQL Node interface that will allow fetching gists by IDs via "node(id)" field (src/schema/Node.js):

const { nodeInterface, nodeField: node, nodesField: nodes } = nodeDefinitions(
  (globalId, context) => {
    const { type, id } = fromGlobalId(globalId);

    switch (type) {
      ...
      case 'Gist':
        return context.gistById.load(id).then(assignType('Gist'));
      default:
        return null;
    }
  },
  obj => {
    switch (getType(obj)) {
      ...
      case 'Gist':
        return require('./GistType').default;
      default:
        return null;
    }
  },
);

Now you should be able to fetch a Gist by ID by using this query:

query {
  node(id: "2e404fe4409ca617a4b6948ea3a67e40") {
    ... on Gist {
      id url description
    }
  }
}

Then you can add "gists" top-level field that fetches multiple gists at once:

{
  type: new GraphQLList(GistType),
  resolve(root, args, context) {
    return fetch('https://api.github.com/gists', {*/ options */})
      .then(x => x.json())
      .then(gists => {
        // Optionally cache them in "gistById" data loader
        gists.forEach(gist => context.gistById.prime(gist.id, gist));
        return gists;
      });
  }
}

So you could fetch them like this:

query {
  gists {
    id url description
  }
}