GraphQL Context

GraphQL has a mechanism to pass information to every resolver. The resolvers are at the core of resolving core logic about how to fetch the data. It is a centerpiece in term of security by allowing to know which user is authenticated and how to filter the information of this particular one. The resolver’s role is the brain to know if information must be stitched in a particular custom way, to reuse information previously requested and to decide which service and endpoints to consume to bring the data in the graph.

The GraphQL’s context allows specifying data when a request is performed and to pass the computed data to every resolver seamlessly. The configuration occurs when specifying the ApolloServerConfig, next to where we configured the GraphQL playground. This time, we need to define a function under the property context. The function that we provide takes a single parameter that is Context.

type Context<T = any> = T;

The context schema is defined by you. As you can see by the definition of the type, from Apollo Core, it is of type T. The context comes with a req property that Express injects. Because Express works with middleware, that can modify the request before reaching Apollo, we can leverage the architecture by having a custom middleware injected the Apache’s header with the user’s information in the request and then read the context object from the context to have the resolvers consume it.

Express calls the auth middleware and Apollo uses the injected data that will be passed to resolvers

Express Middleware

I will skip most of the authentication middleware because it is very unique to Netflix’s security model. However, here is the structure that should be what you use.

export const authorizeUserMiddleware = (req: Request, res: Response, next: NextFunction) => {
    const expressRequest = (req as unknown) as IUserRequest;
    expressRequest.userId = req.headers.injected_header_here_id;
    return next();
};

The code can return an error in the case that you have specific logic that blocks a user to query the GraphQL. GraphQL has many places to block access to a user. The middleware level, at Express server level, is the second higher level you can achieve. The first level is with Apache blocking the request to even reach the NodeJS server that host Express. Later, we will see how to block at the resolvers level which allows blocking a user for a particular entity or even a particular field.

Apollo Context

The Apollo’s context is defined to be of any type. The most pragmatic type is a function. When a function is defined, the function is invoked on every request that Apollo receives. For my particular case, at the moment, the only role of the context function is to pass the information defined in the request object by the Express middleware. I am changing the type with a custom type which will be used by the resolvers.

context: (context: Context) => {
    const requestTyped = context.req as IUserRequest;
    const newContext: GraphQLCustomContext = {
        request: requestTyped
    };
    return newContext;
},

Consuming the Context by Resolvers

Every resolver is a function with three parameters. The parameter that concern the context is the third one. We previously used a hard-coded list of two books. We can modify the resolver to return the list but to change the first entry to have the author name with the data from the injected header. It is not a real use case, but shows that you can use the information from the context in the resolver.

export const bookResolversMap = {
    Query: {
        books: (obj: null, args: {}, context: GraphQLCustomContext) => {
            books[0].author = context.request.headers.injected_header_here_id;
            return books;
        }
    }
};

Summary

GraphQL context is crucial in a GraphQL architecture to bring external information in the graph for wise data resolving. In this article, we saw how to particularly hook an Express middleware that mutate the initial request to open the door to Apollo to build a context with the injected information. In the next article, we will step-out of authentication and improve the Apollo to query with argument opening the door to a more accurate response instead of returning a whole list of entities.

My Other GraphQL Articles

Apollo Server and Secured Playground

In the last article of the series on how to create a GraphQL server with TypeScript and Apollo I demonstrate how easy is to setup the playground. However, there is still a piece that is missing and is authentication. In first post, I explicitly mentioned that every request goes first through Apache that has a special module that handles authentication. Apache will set in the HTTP request some headers with authorization information like a bearer token. At the moment, the playground receives the header but not for any subsequent calls it performs. It leads to HTTP requests that are not authenticated. In my particular case, the request was performing a HTTP 302 trying to redirect to the web portal to get authenticated. Great! The security kick-in! However, how can we force subsequent code to have the header in the playground was the question.

Fortunately, the ApolloServerConfig has the property playground that can be something else than a boolean. It can be a ISettings. The interface has a “request.credentials” and by default “omit”. Changing the default to “same-origin” will carry the missing headers.

playground: {
    settings: {
        "general.betaUpdates": false,
        "editor.theme": "dark",
        "editor.reuseHeaders": true,
        "tracing.hideTracingResponse": false,
        "editor.fontSize": 14,
        "editor.fontFamily": "'Source Code Pro', 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace",
        "request.credentials": "same-origin"
    }
}

 I had to specify additional configuration because the TypeScript definition type has all the field required, so I copy pasted the default value I found under the gear icon in the playground.

The playground’s configurations

Summary

In this article we configured subsequent calls to keep the authentication set in the former request that brought the playground in the browser. In the next article we will see how to read the content of the header to know which user is authenticated. The next step is crucial to have a user experience secured and tailored to the active user.

My Other GraphQL Articles

Apollo Server Playground

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.

Example of writing a query in 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 Articles

Install Apollo Server to host a GraphQL service

This is the second post about my journey on prototyping a GraphQL service to abstract all REST and gRPC services that we have at Netflix Open Connect. You can consult the first article that was describing GraphQL and the high-level architecture to have a better idea of the motivation. In this article, I’ll start diving into how to get started with Apollo. I will not filter out my pain points: there are way too many articles that continue to spin the hype on GraphQL. While GraphQL is great in theory, the practice is never as shiny.

NPM Packages

The first step is to get Apollo and the general GraphQL package. Using NPM like any other libraries is the best way to get the packages. Apollo is divided into several packages, so far, I had to use the main one, the core, and the express library. Apollo is made with TypeScript, thus no type is required. For GraphQL, there is a definition file package available. Because I will use an Express server, I also needed the Express’ type. So far, so good.

npm install –save apollo-server apollo-server-core apollo-server-express graphql
npm install –save-dev @types/graphql @types/express typescript

The whole journey will be strongly typed with TypeScript. GraphQL is having its own schemas and we will see in a future article how we can leverage the type from Proto Buffers (gRPC services), GraphQL schema as TypeScript definition type.

TypeScript

The quickest way to configure TypeScript is to use the initialize command.

tsc --init

I have been using TypeScript for many years and used many different configurations. In 2018, I have been targeting “es5” and used the “esNext” for the module. However, coding in NodeJS with “esNext” is problematic with many libraries. Apollo libraries are in the group of packages that do not support “esNext“. The error “Cannot find module ‘x’ rise. NodeJS supports “commonjs” module, hence I had to switch the “esNext” to “commonjs“. The other characteristic was that the “moduleResolution” was not set explicitly. I assumed that because I am using a TypeScript’s version superior to 3.2 that it was the default. Adding the configuration removed over 10 different problems in the terminal (in VsCode). Here is an extract of the TypeScript tsconfig.json file.

"target": "es5" ,
"module": "commonjs",
"skipLibCheck": true,
"moduleResolution": "node",
"lib": ["es6", "dom", "esnext.asynciterable", "es2015", "es2016", "es2017"],
"sourceMap": true,
"pretty": true,
"strict": true,
"outDir": "build/dist",
"rootDir": "src",
"baseUrl": "src",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true

Express

The Apollo website has a great introduction tutorial that mentions a way to host the GraphQL by simply calling the ApolloServer object. My issue with that approach is that I needed to have custom endpoints. For example, in general, we have a health check endpoint to configure that will be periodically pinged to see if the service is up or down. Also, I wanted to have the flexibility to have any future endpoints on the NodeJS. 

const server = new ApolloServer({ typeDefs });

server.listen().then(({ url }) => {
  console.log(`&#x1f680; Server ready at ${url}`);
});

Without having to look very far, many implementations on the Internet also use Express and use ApolloServer has a middleware. The way to proceed is to create an Express Http server and attach Apollo’s server.

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");
});

It is possible to verify the validity of the actual configuration without configuring Apache. While the objective is to use the authentication mechanism by the Netflix’s Apache module, at the moment nothing require authentication. The excerpt of the Express server on port “graphQlServerPort” which is no port 80. Apache will be using port 80 and will redirect the request to the “graphQlServerPort”. The extract is in the main index.ts file which I have an NPM command that calls TypeScript to build and then calls NodeJS to execute.

"dev": "concurrently \"tsc -w\" \"nodemon build/dist/index.js\""

Indeed, another command in package.json is required when running Apache in Docker, but I will skip that part to focus on GraphQL. The “dev” command start TypeScript in watch mode and has a node monitoring process that will restart on every change of file which occurs every time TypeScript compile. So far, the project is tiny, it takes less than two seconds.

TypeScript and NodeJS Refreshing

Summary

I will stop there for the moment. The Express server is running which is the HTTP server that will host the GraphQL service. TypeScript is configured building the .ts files into .js files that NodeJS can execute. Apollo is attached to Express allowing the API to be called but also to host the playground that we will explore in the next article. So far, it’s been without too much hassle but we have not much configured. Upcoming challenges will strike and the youth of the technology will surface.

My GraphQL Articles

Getting Started with GraphQL for Netflix Open Connect

I recently started an initiative about GraphQL for Netflix Open Connect. Netflix already invests in GraphQL and some of the other teams previously discussed on the Netflix’s Medium page here and there. I’ll approach the writing of my discovery with GraphQL not in hindsight but during my journey.

What is GraphQL?

GraphQL is an open source project that started at Facebook and recently moved to the non-profit Linux Foundation. It started in 2012 and was released publicly in 2015. GraphQL is a query language that allows fetching information in a custom way. A traditional REST endpoint responds with all the information defined by the endpoint. GraphQL allows selecting which field. We can use the metaphor of a SQL query that is fetching with the star operator as the REST equivalence and a select with specific fields to GraphQL.

GraphQL stitches independent endpoints by their natural business relationship. The services endpoints type can be of REST or gRPC — GraphQL blends the different technologies. The abstraction is possible by configuring the GraphQL server to query on multiple endpoints. The consumer is shielded from details of the backend implementation. It means that a user can query for an entity one day, and in the future keep requesting with the same query without having to worry if the backend changed from REST to gRPC. The GraphQL layer that disguises where the response fields come from one source or several sources. This veil allows improving the backend without impacting the frontend which increases the velocity of the consumer and maintainer of the services.

Why using GraphQL?

The main reason for using GraphQL in the perspective of my actual team at Netflix is having a multitude of services that belong to a single realm. There are many cross entities among our tools (scripts and web applications) and many repetitions. With GraphQL we would have one source of truth of each entity and GraphQL would consolidate the need to join the information as requested. A collateral benefit is the reduction of API services.

The second reason is to start using the same schema for entities. Instead of duplicating different version of the same data, we could have a single source of truth owned by the expert of the information and have the client entity generated by the architecture. It is possible to generate entity schema from Protocol Buffer (gRPC’s data structure), to GraphQL, to TypeScript for example. A unified schema would remove mismatch, simplify engineering mental models to a single one and allows a single dialect when talking about a part of our business models. Furthermore, we could reuse entities, mock entity, and unit tests.

A third reason is the flexibility that GraphQL provides by exposing all the information in a non-opinionated payload independently of the backend sources. Every client of the information can request the information desired without needing backend changes. The side effect is a reduction of human involvement. GraphQL opens the doors to future applications to not rely on human resources to create a specialized backend API.

A fourth reason is to improve the performance. At the moment, several REST queries are required to build a client-side sub-world. With GraphQL, a single query can request from multiple sources and return a single query that does not over-fetch information.

A fifth reason is discovery. The centralized source of information that is strongly typed increase the discovery of information and provide a living documentation by identifying which entity related to which one. It is even possible to use an online portal (playground) to query live information to reduce the learning curve by interacting with the data directly. The playground can be open and allows custom queried in an interactive and real-time way without having the consumer to install or having a deep knowledge of our business domain.

A sixth benefit is the reduction of service endpoints consolidation. When requesting information from multiple services, there is always a stitching of the information to create a workable domain of objects. The duplication is spread across all our web applications. With GraphQL, the multiple requests are executed on the server side, consolidated in a single place and returned. The maintainability is improved by having a single place to modify, the productivity is increased by removing duplicated effort among our consumers.

Many other advantages exist that might not be appealing at in short term. For example, GraphQL works on HTTP(s), but also WebSockets. There is also the possibility to manage a safe list of known clients. GraphQL gives a possibility to test schema changes. Versioning is a matter of deprecating fields, no version number involved.

Let’s get started

As the first post, I believe it makes sense to start from the beginning: placing the first brick of the structure. The variety of “material” to settle the foundation can be challenging.  There are many implementations of GraphQL. Per se, GraphQL is a query language and nothing more. The community (and support) mostly motivated the decision to go toward one or another choice. The features of the free-tier and pro-tier (if available) as well as the direction that most of Netflix’s team were already invested or interested to move. Without going in too much detail, I decided to choose Apollo with their NodeJS based solution.

In summary, they have an open source client and server with the possibility to have further features that require a paid subscription. The NodeJS approach is interesting because we use TypeScript for all our front-end application. It also allows us to leverage many NPM packages that we are familiar as well as having a lot of flexibility that the JavaScript ecosystem provides.

We already have several REST services with many endpoints. They are built in several formats, the responses are not always in strict REST flavors, and many schemas exist for similar entities. We also have a limited of gRPC services in which I foresee a potential possibility to auto-generate TypeScript definition files. GraphQL seems to be promising because it allows stitching different technologies and also allows to perform a custom merge of information.

High level architecture

Before going head down into building with Apollo and GraphQL, let’s draw what is going to be built. First, everything must be secured. At Netflix, we have a paved path that handles the authentication and it is baken within Apache. As mentioned, Apollo is leveraging NodeJS. This is not an issue because we can deploy on the server the Apache server that will redirect all HTTP requests to NodeJS. Having Apache as the front server wrap NodeJS for the security. NodeJS will not be accessed directly outside the machine and only Apache will be able to communicate with NodeJS. In the eventuality that there is a bug and NodeJS is accessible, the request will not go very far: it won’t be authenticated hence will fail on the actual web service.

GraphQL hosted in NodeJS

To simplify the development, I’ll reuse a recipe that I have been using since I joined Netflix which is to develop with a Docker container. The major gain is that I do not have to run Apache locally which could interfere with many other applications that must use Apache as well. 

Summary

I’ll write down many future posts about how the initial vision change and how I am implementing the whole solution. I hope that this prototype will see the day and will spread as broad as I expect. I foresee a huge gain in term of auto-generation of TypeScript for all our web application from GraphQL. I foresee also a lot of code generation from Protobuf from our services that are gRPC allowing a good developpement experience at the NodeJS layer. 

My Previous GraphQL Articles