Thomas Step

This is where I share my thoughts and experiences that I encounter developing software.

Blog


Blog Categories


About Me


Projects


View My GitHub Profile


View My GitLab Profile


View My LinkedIn Profile


3 June 2020

Using Apollo Datasources Outside of Apollo

by Thomas

I have been using Apollo Server for a while now, and one of the tools that they offer is the RESTDataSource class, which I have used extensively. There were a couple use cases I have run into where I needed to write one off scripts that interacted with the same data sources as my graphql server. The most straightforward way I could think of doing this was to use the classes I had already created that extended RESTDataSource. It seems simple enough, but there is one caveat that is worth noting before you can use a RESTDataSource outside of Apollo Server. I will start off by using the example featured in the npm page and the github readme.

const { RESTDataSource } = require('apollo-datasource-rest');

class MoviesAPI extends RESTDataSource {
  constructor() {
    super();
    this.baseURL = 'https://movies-api.example.com/';
  }

  async getMovie(id) {
    return this.get(`movies/${id}`);
  }

  async getMostViewedMovies(limit = 10) {
    const data = await this.get('movies', {
      per_page: limit,
      order_by: 'most_viewed',
    });
    return data.results;
  }
}

If you wanted to create an instance of this class to take advantage of what you have already written, you will need to initialize it first. That would look like this:

const movies = new MoviesAPI();
movies.initialize({});
movies.getMovie(1);

If you try calling a function that uses a REST method (get, post, etc.) before calling initialize() first, then you might see an error that looks like this.

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'fetch' of undefined

The reason that the calls fail if the DataSource is not initialized is because there is never any HTTPCache created for the instance of RESTDataSource. This is the source code for initialize(), and it can also be seen on GitHub here.

initialize(config: DataSourceConfig<TContext>): void {
  this.context = config.context;
  this.httpCache = new HTTPCache(config.cache, this.httpFetch);
}

The RESTDataSource initialize() call creates this.HTTPCache which in turn has a member function called fetch. Whenever a REST method from the class is called, it calls this.fetch(), which in turn calls this.HTTPCache.fetch(). This is the cause for the error that you see if you try to call a function from a RESTDataSource without first initializing it. I tried to give relevant links to their source code in GitHub, depending on when you read this though it might be better to go through the source yourself. Either way, this was the problem I came across, the solution I found for using Apollo DataSource outside of an Apollo Server.

tags: dev - javascript