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
datasourcesfunction, causing shared state across requests. - Forgetting to call
initialize()or not properly settingthis.contextin the datasource. - Trying to access datasources directly instead of via
context.dataSourcesin 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
DataSourceorRESTDataSourcefor your datasource classes. - Return new datasource instances in the
datasourcesfunction. - 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.