Apollo Server Playground
Posted on: 2019-01-22
Apollo comes with a handy playground. The playground is simple web portal that allows a rich experience to craft a GraphQL query against the Apollo GraphQL server. The interactive system gives autocomplete, schema discovery and display the response. It is a very valuable tool when developing because you do not need to use any external tool to test the GraphQL solution.
For the third post on the series on GraphQL we will explore the playground. Fortunately, it does not require too much work. However, I got stuck and was astonished to see that some people got in the same trouble I had to go in 2016 -- two years before me. I'll describe how I configured the playground and highlight a pitfall that seems to be common and unfixed by default.
In the previous post, we had a very limited Apollo and Express configuration like the following code.
import express, { Request, Response } from "express";
const app = express();
app.get("/healthcheck", (req: Request, res: Response) => {
res.status(200).send("ok");
});
const server = new ApolloServer(await apolloServerConfig());
server.applyMiddleware({ app, path: endpoint, cors: true });
app.listen(endpoints.graphQlServerPort, () => {
console.log("Up-and-running");
});
To keep the code tidy, the portion that instantiate the ApolloServer class into a server instance is extracted into a function. The result is a index.ts file more readable because we will add a few configurations to the instantiation of Apollo.
import express, { Request, Response } from "express";
const app = express();
app.get("/healthcheck", (req: Request, res: Response) => {
res.status(200).send("ok");
});
installGraph("/api/graph", app).then(() => {
app.listen(endpoints.graphQlServerPort, () => {
console.log("Up-and-running");
});
});
The installGraph
function takes two parameters. The first one is the path under the GraphQL is reachable. The string can be to any URL you want. The second one is the Express server. The function contains the two lines that we had before with a small modification concerning the parameter passed to the server.
const server = new ApolloServer(await apolloServerConfig());
server.applyMiddleware({ app, path: endpoint, cors: true });
The configuration function is asynchronous, but does not need to be. I have some configuration that requires to perform a call that is async for authentication purposes. The key idea is that in a single function you will configure all you Apollo GraphQL server. The main configuration is to set the typeDefs and resolvers. For the moment, we can use some fake data for both but later we will connect to read data source like REST services and gRPC services. A simple definition can be of a book with a title and an author. The resolver can return the whol list of book.
import { gql } from "apollo-server-core";
// Type Definition
export const typeDefs = gql`
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`;
// Fake data source
export const books = [
{
title: "Harry Potter and the Chamber of Secrets",
author: "J.K. Rowling",
},
{
title: "Jurassic Park",
author: "Michael Crichton",
},
];
// Resolver
export const resolvers = {
Query: {
books: (obj: null, args: {}, context: {}) => {
return books;
},
},
};
When the resolver and the type definition are coded, you can insert them in the Apollo Server.
const serverConfig: ApolloServerConfig = {
typeDefs,
resolvers,
playground: true,
};
There are few caveats with the code above. The first one is that it has a single type definition and a single resolver. The second is the lack of authentication. We also do not pass any parameter that would give the possibility to fetch a single entity instead of a full list. Finally, the context is not set hence we do not know who is making the request and cannot resolve the information for a particular user. Nevertheless, the playground is activated. By running the code and going to the endpoint passed by parameter, in my case "/api/graph" it is possible to query from any HTTP request but by going into the browser and use the playground.
Summary
This article is a little bit deceiving. Not that I lied, but that I know that few things does not work. For example, with the current implementation, the code does not scale well for GraphQL type definitions or resolvers. The playground works, but if you are using an authenticated API, it will fail. In the next article I will modify the code of this article to make it scales better to have many GraphQL type definitions and resolvers as well as bringing a strongly typed TypeScript context for authentication purposes but also to allow returning from GraphQL information that belong to only the authenticated user.
My Other GraphQL Blog Posts
- Getting Started with GraphQL for Netflix Open Connect
- Install Apollo Server to host a GraphQL service
- Apollo Server and Secured Playground
- GraphQL Context
- GraphQL Query with Argument
- Apollo GraphQL Resolvers and Data Source separation
- How to setup a TypeScript, NodeJS, Express Apollo Server to easy debugging with VsCode
- GraphQL Resolvers with Apollo
- Configuring Apollo Playground and API on two different URL
- How to automatically generate TypeScript for consumers of your GraphQL
- GraphQL and HTTP Telemetry
- GraphQL and TypeScript/React