Search code examples
graphqlapolloapollo-serverdataloader

In Apollo GraphQL how to access Datasources inside Dataloader?


I'm new to GraphQL and I started using Apollo GraphQL. To test this basically I'm wrapping the GraphQL around Star Wars API (SWAPI.dev). I'm using Apollo RESTDataSource to make calls to Star Wars API. In 'People' resource there's an array of 'Planets' and I want to batch load this using Dataloader.

Inside the Dataloader I need to be able to batch for data and I need to use my Datasources to actually get the data using batching. But I can't find a way to access datasources in the Dataloader.

My Dataloader is as follows,

const DataLoader = require('dataloader');

const batchHomeworlds = async (urls) => {

    // How to access dataSources?
    //homeworlds = await dataSources.starWarsAPI.getResourcesBatch(urls)

    // Hardcoded just for testing
    homeworlds = [{url: 'http://swapi.dev/api/planets/1/', name: 'Test'}]

    const homeworldUrlMap = {};

    homeworlds.forEach(homeworld => {
        homeworldUrlMap[homeworld.url] = homeworld;
    });

    return urls.map(url => homeworldUrlMap[url])
};

module.exports = () => new DataLoader(batchHomeworlds);

Apollo Server initialization

const server = new ApolloServer({ 
  schema,
  dataSources: () => ({
    starWarsAPI: new StarWarsAPI()
  }),
  context: () => ({
    homeworldLoader:  homeworldLoader()
  })
});

Resolver that uses the Dataloader is as follows,

homeworld_planet: (parent, args, { dataSources, homeworldLoader }, info) => {
      return homeworldLoader.load(parent.homeworld)
    }

Any help is greatly appreciated! Thanks!


Solution

  • The usual approach to give access to shared objects in dataloader functions is to put them into the closure of the batch function:

    module.exports = function createDataloaders(dataSources) {
      const batchHomeworlds = async (urls) => {
        const homeworlds = await dataSources.starWarsAPI.getResourcesBatch(urls);
        return urls.map(url => homeworlds.find(h => h.url === url));
      };
    
      return {
        homeworldLoader: new Dataloader(batchHomeworlds),
      }
    };
    

    When creating the dataloaders you now have to supply the dataSources. Maybe don't get to attached to the data sources pattern in the beginning.