When building a GraphQL server with Apollo, you might come across scenarios where you need to integrate with external REST micro services. Apollo provides a convenient way to handle such integrations
What is RESTDataSource?
RESTDataSource
is a class provided by Apollo that helps simplify making HTTP requests to RESTful services. It abstracts away many of the common HTTP request tasks and provides methods to interact with the API endpoints.
Let’s start by creating a Services
class that extends RESTDataSource
. This class will encapsulate the logic for making requests to your RESTful services.
// Services.ts
import { RESTDataSource } from "apollo-datasource-rest";
export class Services extends RESTDataSource {
override baseURL = process.env.API_URL + "/api";
async saveListing(body: SaveListingPayload): Promise<{ processed: boolean }> {
return this.post(`listings`, body);
}
}
In this example, we’ve defined a method, saveListing
that use the post
method from RESTDataSource
to send POST requests to the respective endpoint.
Integrating Services with Apollo Server
Now that we have our Services
class set up, let’s integrate it with your Apollo GraphQL server.
Update the dataSources
configuration in your Apollo server setup:
export interface ApolloContext extends BaseContext {
authorization?: string;
jwt?: jwt.JwtPayload | null | string;
dataSources: {
++ services: Services;
};
}
const server = new ApolloServer({
resolvers,
typeDefs,
introspection: true,
plugins: [authenticationMiddleware(["LoginMutation", "Login"])],
context: async (req, res) => ({
req,
res,
authorization: req?.headers?.authorization,
jwt: decode(req?.headers?.authorization),
dataSources: {
++ services: new Services(),
},
}),
});
Using the RESTDataSource Methods
With the Services
class integrated into your Apollo server, you can now use its methods in your resolvers.
For example, let’s assume you have a resolver that needs to save a listing:
// resolvers/saveListing.ts
import { ApolloContext } from "@/pages/api/graphql";
import { ApolloError } from "apollo-server";
import { MutationSaveListingArgs } from "__generated__/graphql";
export async function saveListing(
_: unknown,
{ input }: MutationSaveListingArgs,
{ dataSources: { services }, jwt }: ApolloContext
): Promise<ApolloError | SaveListingResponse> {
try {
return await services.saveListing({
...input,
user: { uuid: (jwt as { uuid: string })?.uuid },
});
} catch (error) {
throw new ApolloError("Failed to save listing.", "SAVE_LISTING_ERROR");
}
}
In this example, the saveListing
resolver uses the services.saveListing
method to send the necessary data to the RESTful service and receives the response.
This approach allows you to encapsulate the HTTP request logic, making your resolvers cleaner and more focused on your business logic. With the RESTDataSource
, you have a powerful tool to streamline your GraphQL server’s interaction with RESTful APIs.
Happy Hacking !