0
0
GraphqlHow-ToBeginner · 4 min read

How to Use Datasources in Apollo Server for GraphQL APIs

In Apollo Server, you use datasources by creating classes that extend DataSource and then adding them to the server configuration under the datasources option. This lets you organize data fetching logic cleanly and access it in your resolvers via the context.
📐

Syntax

To use datasources in Apollo Server, define a class that extends DataSource. Then, provide a datasources function in the Apollo Server constructor that returns an object mapping datasource names to instances. Access these datasources in resolvers through the context parameter.

  • DataSource class: Encapsulates data fetching logic.
  • datasources function: Returns datasource instances for each request.
  • context: Provides access to datasources inside resolvers.
javascript
const { ApolloServer, gql } = require('apollo-server');
const { DataSource } = require('apollo-datasource');

class MyAPI extends DataSource {
  initialize(config) {
    this.context = config.context;
  }
  // Define methods to fetch data here
}

const server = new ApolloServer({
  typeDefs,
  resolvers,
  datasources: () => ({
    myAPI: new MyAPI()
  }),
  context: () => ({ /* user info, auth, etc. */ })
});
💻

Example

This example shows a simple Apollo Server with a datasource that fetches user data from a mock API. The datasource class UserAPI has a method getUser that returns user info. The resolver calls this method via context.dataSources.userAPI.

javascript
const { ApolloServer, gql } = require('apollo-server');
const { RESTDataSource } = require('apollo-datasource-rest');

// Define GraphQL schema
const typeDefs = gql`
  type User {
    id: ID!
    name: String
  }
  type Query {
    user(id: ID!): User
  }
`;

// Create a REST datasource
class UserAPI extends RESTDataSource {
  constructor() {
    super();
    this.baseURL = 'https://jsonplaceholder.typicode.com/';
  }

  async getUser(id) {
    return this.get(`users/${id}`);
  }
}

// Define resolvers
const resolvers = {
  Query: {
    user: async (_source, { id }, { dataSources }) => {
      return dataSources.userAPI.getUser(id);
    }
  }
};

// Create Apollo Server
const server = new ApolloServer({
  typeDefs,
  resolvers,
  datasources: () => ({
    userAPI: new UserAPI()
  })
});

// Start server
server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);
});
Output
Server ready at http://localhost:4000/
⚠️

Common Pitfalls

Common mistakes when using datasources in Apollo Server include:

  • Not returning a new instance of the datasource in the datasources function, causing shared state across requests.
  • Forgetting to call initialize() or not properly setting this.context in the datasource.
  • Trying to access datasources directly instead of via context.dataSources in resolvers.

Always return fresh datasource instances per request and access them through the context parameter.

javascript
/* Wrong way: Reusing datasource instance */
const userAPI = new UserAPI();
const server = new ApolloServer({
  datasources: () => ({
    userAPI // same instance reused
  })
});

/* Right way: Return new instance each time */
const serverCorrect = new ApolloServer({
  datasources: () => ({
    userAPI: new UserAPI()
  })
});
📊

Quick Reference

Summary tips for using datasources in Apollo Server:

  • Extend DataSource or RESTDataSource for your datasource classes.
  • Return new datasource instances in the datasources function.
  • Access datasources in resolvers via context.dataSources.
  • Use initialize() to set up context or other request-specific info.

Key Takeaways

Create datasource classes extending Apollo's DataSource or RESTDataSource to organize data fetching.
Always return new datasource instances in the Apollo Server's datasources function to avoid shared state.
Access datasources inside resolvers through the context parameter as context.dataSources.
Use the initialize method in your datasource to set context or other request-specific data.
Avoid reusing datasource instances across requests to prevent data leakage and bugs.