How to Pass Value to useCallback in React Hooks

UseCallback allows having the same reference for a call back function which has the benefit of only changing when something changes. This is primordial when callbacks are passed down the React component chain to avoid component to be rendered without an actual real reason causing performance issue. The following snippet of code shows a simple button that when clicked invokes an action that set the name to “test”. You can imagine that in a real scenario that the string would come from a real source instead of being hardcoded.

<button
  onClick={() => {
    dispatch(AppActions.setName("test"));
  }}
>

The action can often be handled without passing data, or by passing a React’s property and hence can access it from the handler of the action. However, in some cases, where the value is not accessible directly from the outer scope of the handler function, it means that we need to pass by parameter the value. I am reusing a Code Sandbox slightly modified to have the useCallback with a value passed down. The use of useCallback or simply the refactoring of the above snippet into a function that is not directly bound to the onClick is similar. We are moving the accessible scope. When the function is inline, the function can access anything that defined the button. It can be the React’s properties, or the “map” index if it was inside a loop or else. However, extracting the function out require some minor change to still have access to the value.

 const setName = useCallback(() => {
    dispatch(AppActions.setName("test"));
 }, []);

A quick change with React Hooks to produce the desired scenario is to use useCallback at the top of the component and access it directly in the onClick function callback.

<button onClick={setName}>Change name</button>

At the moment, it works. However, we are not passing any information. Let’s imagine that we cannot access the data directly from the useCallback, how can we still invoke this one?

const setName = useCallback((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    dispatch(AppActions.setName("test"));
  }, []);

The idea is to have a callback that return a function that as on its turn the input event.

<button onClick={setName("Testing Name")}>Change name</button>

The invocation code change by passing the data. In that example, it is a string, but you can imagine that you are passing the index of the map function or data coming from a source inaccessible from the callback function.

  const setName = useCallback(
    (name: string) => (
      event: React.MouseEvent<HTMLButtonElement, MouseEvent>
    ) => {
      dispatch(AppActions.setName(name));
    },
    []
  );

My rule of thumb is that I do not need to have this convoluted definition if I am accessing directly properties of the component. Otherwise, I am passing the data needed. I always define the type, which gives me a good quick view about what is passed (name is a string and the event is a mouse event) without having to rummage the code. Here is the code sand box to play with the code of this article.

TypeScript Exhaustive Check your Reducer

A few weeks ago, I wrote about how to use React Hooks useReducer with TypeScript. The natural follow-up for many is to ensure that the set of action allowed is all served with the reducer. Not only it helps to tidy up the accepted actions by reducers when building the reducer, it also help ensuring during the lifetime of the reducer that the list of action remains up-to-date.

If we recall, the reducer is taking the state and the action. The action was typed to be a list of function that must be part of the AppActions. An utility type was used that allowed to union many set of action, but not used since we were using a single type. Nonetheless, everything was in place to ensure a flexible configuration of actions.

export type AcceptedActions = ActionsUnion<typeof AppActions>;
export function appReducer(
  state: AppReducerState,
  action: AcceptedActions
): AppReducerState {
  switch (action.type) {
    case ACTION_INCREASE_COUNT:
      return {
        ...state,
        clickCount: state.clickCount + 1
      };
    case ACTION_SET_NAME:
      return {
        ...state,
        activeEntity: { ...state.activeEntity, ...{ name: action.payload } }
      };
  }
  return state;
}

While we cannot add subjective case with action not defined in the AcceptedActions type, the weakness of the code is that we can remove one of the two cases without being noticed. Ideally, we would want to ensure that all actions are defined. In the case that an action is not anymore required that we would need to remove it from the list of action.

The solution require only a few amount of lines. First, you may already have have the core of the needed logic: an exhaustive check function. I have covered many months ago the idea of an exhaustive check in this article. In short, it is a function that should not be reached, when TypeScript found a logical path that can reach the code, the code will not compile.

export function exhaustiveCheck(check: never, throwError: boolean = false): never {
    if (throwError) {
        throw new Error(`ERROR! The value ${JSON.stringify(check)} should be of type never.`);
    }
    return check;
}

The use of reducer and TypeScript’s exhaustive check pattern is similar to what we would have done for checking if all values are covered on an Enum. The code needs to have a default case which we do not expect the code go fallthrough.

The two new lines:

    default:
      exhaustiveCheck(action);

Removing a required action cause TypeScript to go in the exhaustive check and since the function is marked to accept a never argument does not compile.

TypeScript catching the missing action

I have updated the original code sandbox. Click on the reducer.ts and try to remove on the of action.

In conclusion, the solution might not be ideal for you if you have all your actions into a huge function, or if you do not even group your action might not be even possible. However, grouping actions tidy up your code by having a better idea of what possible actions are expected in different domain of business your application handles. It is not much more work, and it self-document the code. The exhaustive check is an additional step to maintain order.

The authorization and authentication in GraphQL

Implementing a service that covers many systems might be frightful in term of data exposition. While wandering the Internet for resources about GraphQL and security, we often see cases where the security is not paramount — it is easier to ignore security. The reality is that most corporation that desire to bring GraphQL will also need to secure the information. This article sheds light on how I approached the security in my implementation of GraphQL at Netflix for Open Connect.

Prelude

In an ideal world, we have the GraphQL server getting the authorization from the corporate security infrastructure and the GraphQL delegate downstream to the actual data source the responsibility of returning an error. For example, if the data source is a REST API, the token of the user is used for the call, hence can return an HTTP code 401 and GraphQL will handle the error. However, in maybe the GraphQL exposes some internal services that were secured only by the premise that it was under a VPS (virtual private server). Meaning that not validation is actually performed. In that case, some custom code is required by the executioner of the service: GraphQL. Another case could be that the security is by a specific group of entity (organization, user, etc) meaning that you do not want user A to access user B information. Again, a strong security model would perform the validation at the source (Rest, SQL views, etc) but in the real world, it is not always the case. To mitigate the possibility of security issues among the sea of services that was cover in my scenario, the security was placed in GraphQL. Meanwhile, further modification in the data sources could be planned and put in place without compromising the delivery of the GraphQL server.

Exploring the possibilities

One strength of GraphQL is the flexibility. The flexibility nature remains true for security and it opens many doors to where to secure the service. As mentioned earlier, the NodeJS server that host Apollo is behind Apache. The reason is that at Netflix, we have many tools integrated within Apache to secure the user like single-sign-on, OpenID Connect and OAuth 2.0. The Apache module is great for authentication but not for authorizing. It does check if the user is one that can access the GraphQL but does not discriminate on which information the user can consult.

Flow of the request from user to services that contain the information

Apache gives information about the user and provides the additional HTTP headers to NodeJS. The first stop is a custom NodeJS Express middleware. The middleware is a piece of code executed in each request. The middleware check if the user is a Netflix employee with a specific grant right. If that is the case, it marks a particular field in an enhanced request object to signal the user as “authorized for full access.” The idea is to avoid every future validation that can be performance costly. This shortcut works well because the Apache module can be trusted with its information. It might not work well in your organization, thus do your homework. The next stop is at the GraphQL context. In my case, I have no validation to do at that level because I did the check in the NodeJS Express middleware. However, if you are not using NodeJS, it would be the place to do HTTP request checks. However, I instantiate a secure object at that level that contains functions that check particular lists of objects. The lists of objects are specific ids of secured entities that the user has access. Then, the context performs a query on specific backend services to fetch what objects ids the users can access. The list goes in the request. The idea is to have before the user reaches the resolver a well-defined list of authorized entities and ids.

It is possible to perform at the resolver checks, but the problem is that if you are not querying for the field that contains the ids that the user can access that you will not have the value available. For example, if a user can only access the data of the organization that he/she belongs and that the user requests for the organization by id for its name then you could block. But, if the user request for a sub-entity, for example a contact and then in the query’s tree the name of the organization, without the organization id, then the resolver cannot check if the organization’s data belong or not to the authorized ids.

Finally, the place I found the best to handle authorization is at the data loaders level where every HTTP requests to service are performed. Upon reception of a query, the data is examined to check if the payload contains information from the entities we want secure. If the response contains an entity that does not belong to the user, an exception is thrown and GraphQL bubble up the exception to the resolver who initiated the request. GraphQL handles the exception properly and your message is given to the user.

Conclusion

The solution is not ideal because it requires the user to have an additional call, per service, to have a list of entities and ids. I opted to have the GraphQL cache all the entities-ids per user in a server cache (not a request cache) for few minutes. The solution has a flaw that the request is still performed to the service. The reason is the lack of transparency from an entity B on entity A before getting the data. Nonetheless, it secures because the response does not go beyond NodeJS, it is not cached either. These loops are required because of weakness at the leaf of the architecture: the service that has access to the data. As a reminder, even if you are building an internal service that is secured by a network, it is always better to not rely on that infrastructure and to perform database checks. The future is never known, infrastructure change, security change, a potential consumer of the information evolve, and we never know when something will be exposed. For future resiliency and for an optimal defense: always authorize at the source.

My Other GraphQL Articles

How to consume GraphQL in TypeScript and React

In this article I’ll cover two different approach concerning rendering information coming from a GraphQL server in React while being strongly typed.

Approach 1: The normal fetch

The first approach is the one I prefer because it is not intrusive. It is very similar of to do a normal REST Ajax call. It can be swapped from an existing fetch command that is using not GraphQL without having to change much. The approach is frontend framework agnostic, meaning that you can use it outside React. Furthermore, this approach works well in a middleware if you are using Redux, but can be directly used in you custom “service” layer or when a component is mounted — you choose.

The first step is to get some NPM packages. In this approach, I am using two packages related to GraphQL: the Apollo-boost and the graphql-tag.

import ApolloClient, { ApolloQueryResult } from "apollo-boost";
import { Proto } from "autogenerated/octoolstypes";
import gql from "graphql-tag";
import React from "react";

You then need to create an ApolloClient which is the library that will perform the query. See the ApolloClient as an HTTP request library, similar to Axios. It lets you specify the URL to perform the POST HTTP request, but also custom headers. For example, I am specifying a bearer token to have the request authenticated.

this.client = new ApolloClient({
    uri: "/api/graphql",
    headers: {
        authorization: `Bearer ${this.props.token}`
    }
});

The next step is to have the query executed. This is where you can swap your existing fetching code with the ApolloClient.

(async () => {
    try {
        const result: ApolloQueryResult<Proto.Query> = await this.client.query<Proto.Query>({
            query: gql`
                query Proto {
                    org(orgId:orgIdParam) {
                        name
                    }
                }
            `
        });
        if (result.data.org &amp;&amp; result.data.org.name) {
             // Do something with result.data.org.name
        }
    } catch (error) {
        console.error(error.networkError.bodyText);
    }
})();

That’s it. Very simple, easy to understand because it is similar to most fetching pattern. The ApolloQueryResult takes a generic type which is the format of the gql. It means that when building for the first time the query that you might not want to explicitly specify the type because it does not exist. As discussed in a previous article, there is tool that will scan the gql query and generate the type for you.

Approach 2: Strongly bound to React

The second approach is my less favorite. I favor the first one because I like separating my view from my logic. It is easier to unit test, and the separation of concern make the code easier to understand and refactor. Nonetheless, the option is available and worth exploring.

The second approach use an Apollo component that will wrap the application. It is similar to the React-Redux provider. It takes a single property which is the client, that is the same as provided in the first approach.

public render(): JSX.Element {
    return (
        <ApolloProvider client={this.client}>
            <ConnectedRouter history={history}>
                <AppRouted />
            </ConnectedRouter>
        </ApolloProvider>
    );
}

The difference is that because we have the client connected in the ApolloProvider that any React component underneath has access to the possibility of querying by creating a Query component.

<Query<Proto2.Query>
    query={gql`
        query Proto2 {
            org(orgId: orgIdParam {
                name
            }
        }
    `}
>
    {queryResult => {
        if (queryResult.loading) {
            return "Loading";
        }
        if (queryResult.error) {
            return "Error";
        }
        if (queryResult.data === undefined || queryResult.data.org === null) {
            return <p>None</p>;
        }

        return (
            <div>
                <h5>Name:</h5>
                <p>{queryResult.data.org.name}</p>
            </div>
        );
    }}
</Query>

Once again, the Query is strongly typed by using the gql defined in the query parameter of the query component. Until the type is generated, which mean that the gql query has been picked up by the script that build the TypeScript file, the query cannot be explicitly typed. However, once it done, any future change will catch on. This approach has the query executed every time the container of the Query component is rendered which mean that future optimization, like having a caching policy specified in the ApolloClient might be a good thing.

Wrap-up

There are more than two ways to bind GraphQL data into your React application while having the benefice of being strongly Typed. The first approach is more agnostic, the second embrace React with a component to handle a query. As long as you are comfortable, either does the job. I recommend using the former approach because it is flexible without having your fetching code dependent on React but otherwise, the end result of a strongly typed code is the same.

GraphQL Posts

GraphQL Extension to Collect HTTP and Resolvers Telemetry

The more my graph was increasing, the more resolvers I built. The more resolvers I had, the more data loaders I created, the more HTTP endpoints I had to call and so on. The complexity of the code was rising as well as the possibility to have a catastrophic amount of HTTP requests to be performed by GraphQL. The amount of log by using the console was not only polluting the source code by having a line in each resolver and HTTP method but also couldn’t make it easy to collect the data for future analysis or to emergency cancellation of a GraphQL query if the amount of HTTP rise beyond a reasonable threshold.

The idea I had was to see if there is a way to hook into GraphQL to collect the data at a higher level instead of being at each function. I am using the Apollo library and the answer is yes! There is an experimental feature named “extension”. The documentation is dry and does not explain much but with some breakpoint and Visual Studio Code, I was able to build a simple extension in a few hours. Here is the result.

A GraphQL Request with its HTTP requests

The first requirement is to create the extension. It must inherit the GraphQLExtension class which is generic. The generic type needs to be your context type. Having access to the context is primordiale because it gives access to your user information. I assume that once authenticated the user is set in the context. Also, it gives you the possibility to inject statistic into the context throughout the exploration of the graph. In my case, I am using the context to collect information at my data service layer where all the HTTP requests are performed.

export class DevConsole<TContext extends ApolloConfigurationContext> implements GraphQLExtension<TContext>

There is two importants function that you can override. The first one is “requestDidStart” which is invoked when a GraphQL request is made. It means that when a context is created and it that case a “request” is the GraphQL request and not all HTTP request performed by GraphQL during that GraphQL’s request. The function return a function. The return function is invoked when the request is completed. It is the place to output into the console all your statistic or to send the information to your telemetry system.

public requestDidStart(o: {
    request: Pick<Request, "url" | "method" | "headers">;
    queryString?: string;
    parsedQuery?: DocumentNode;
    operationName?: string;
    variables?: { [key: string]: any };
    persistedQueryHit?: boolean;
    persistedQueryRegister?: boolean;
    context: TContext;
    requestContext: GraphQLRequestContext<TContext>;
}) {
    console.log("New GraphQL requested started");
    return () => {
        const yourContextData = o.context
        console.log("Your data can be sent here");
    };
}

The second function is named “willResolveField” and is executed at every node of your graph. You can know the parent field and your field.

willResolveField(source: any, args: { [argName: string]: any }, context: TContext, info: GraphQLResolveInfo) {
    // Info has the field name and parentType.name
    return (error: Error | null, result: any) => {
        // ...
    };
}

The next step is to plug the extension into Apollo GraphQL. The property “extensions” of ApolloServerConfig takes an array of extension.

const serverConfig: ApolloServerConfig = {
    // ...,
    extensions: [() => new DevConsole()]
};

I am using the RESTDataSource of Apollo as well to perform all HTTP request. The abstract class has the GraphQL’s context. If you override the function willSendRequest, you can then have a global hook into all HTTP request. In that function, I am populating a property of my context that I named “stats” where I am storing each URL and parameters.

public willSendRequest(request: RequestOptions) {
    const stats = this.context.stats;
    // push data in the stats object
}

The documentation could be better in term of defining all the possibility. Nevertheless, with some breakpoints and a little bit of time I was quite satisfied to see what can be done. You can do much more than what proposed, for instance, you can calculate the payload size and get more insight into what is not efficient. For example, I realized in the process of creating another exception that was throwing an exception when a maximum threshold of HTTP request was reached was still letting GraphQL continue its traversal causing the exception to occurs on every future node. The solution was to clean up the response of redundant error using the overload function willSendResponse.

Bonus: Getting the size of the payload

There is a lot of possibility to get a clear view of what is happening behind the scene for maintainers and developers of the GraphQL service. The detail does not matter directly for the consumer who care about getting the data fast and accurately in the format requested and not about the complexity. However, the complexity if not well exposed to the team who own the service can be costly in term of resources. It is very easy to fall into the trap of assuming that everything goes as expected in a world where every GraphQL request is unique and can surface a scenario not well covered.

Previous GraphQL Posts

How to automatically generate TypeScript for consumer of your GraphQL

One strength of GraphQL is that it has types. In an ideal world, the consumer of the GraphQL would receive the payload strongly typed. The reason that it is not the case is natural. The data that is moving from the server to the client who invoked the query receives a JSON format that does not have any notion of type. However, the client who call the GraphQL know exactly which fields he wants to consume and GraphQL maps each queried fields to a type.

Objectives

The idea of this article is to let the user who call the GraphQL server to get a tailored object that is only for the field requested but also strongly typed for the field needed. It means that if the user request field A, B, and C of an object that has A, B,C, D, E, that the type that will be automatically generated will be only with A, B, C. While it might look that the generated type is not representing the real object, it reflects exactly the data that can be used. There is no need to have a generated object that you could not use.

Constraints

Many articles discuss about introspection and how types can be generated by having the consumer connect directly to GraphQL server to fetch the schema. I had the constraint that I could not do it for security reason, hence I had to expose the schema by the server into another way and have the consumer uses the generated merged schemas.

Server Steps

On the server side, one step is required: exposing the schemas into a unified schema (file) that can be shared. By generating the type every time the server is compiled, the schema remains in synchronization. Hence, we do not lose the freshness of being connected directly to GraphQL.

I created a script in the package.json that execute a TypeScript script.

"generateunifiedschema": "ts-node src/scripts/mergeAllGraphqlSchemas.ts",

The code in the TypeScript file is simple — really simple. Here is the whole code:

import fs from "fs";
import { fileLoader, mergeTypes } from "merge-graphql-schemas";
import path from "path";
const documentTypeDefs = fileLoader("src/**/*.graphql");
const mergedSchema = mergeTypes(documentTypeDefs);
const typesPath = "output_types";
const schemaPath = path.join(typesPath, "allSchema.graphql");
fs.writeFileSync(schemaPath, mergedSchema);

It uses the library merge-graphql-schemas and search for all individual schema that is spread inside the project. The result goes outside in a folder. That’s it. In my case, that generated file is available internal at Netflix but not exposed outside. It means that every developers that consume the GraphQL service can download the schema, create query in their TypeScript code and use the unified schema to generate their code.

Client Steps

Each consumer will have to do few steps. First, they need to download the unified schemas. Second, they need to write their GraphQL query and use gql. The gql allows to have a library that will scan the TypeScript file for gql (GraphQL Query) and will generate the appropriate TypeScript definition for the response data.

Download Unified Schema

The download step is a matter of using curl. I create a simple bash file:

curl -X GET \
  http://retracted/allSchema.graphql \
  -H 'accept: text/plain, */*' \
  --silent \
  --output allSchema.graphql

Query the GraphQL

The next step is to write the client code to query the data. There is many ways to do it, I’ll demonstrate one but will not go in detail in this article.

async () => {
            try {
                const result: ApolloQueryResult<Proto.Query> = await this.client.query<Proto.Query>({
                    query: gql`
                        query Proto {
                            org(orgId: 0) {
                                name
                            }
                        }
                    `
                });
                if (result.data.org &amp;&amp; result.data.org.name) {
                    this.setState({
                        longName: result.data.org.name
                    });
                }
            } catch (error) {
                console.error(error.networkError.bodyText);
            }
        }

At that point, your may wonder what is “Proto.Query” type and how come the result is strongly typed. The “Proto.Query” is the type that will be generated from the query specified in the client.query. The gql contains a query name which is translated into a TypeScript’s namespace. It is important to name each query differently because of potential collisions. In my case, the org entity has only a single field, but later I might request more which will generate another org. A good way is to not call it “Proto” but something more relevant. For example, “Financial” or “Inventory” depending on the usage of the entity. Still, how do we generate the object.

Generate the TypeScript type

The generation is done by using a library named graphql-code-generator which scan the TypeScript file for gql and uses the unified schema (or could work by directly connecting to the GraphQL) and output in a specified folder the type. It means that the first time you are writing the gql, you should not strongly type the ApolloQueryResult, then will have access to the type. Then, every change in the type will mend the existing type which is a great experience. For example, removing in the gql a field that is being used in TypeScript will make the code not compile. The “graphql-code-generator” library has a bin that you can use in your package.json to read the codegen.yml file with your custom configuration. I added two scripts. One that analyzes the TypeScript files and generates and another one that I use while developing who constantly check in the background to generate types.

"generatetypes": "gql-gen --config graphql/codegen.yml",
"generatetypes:watch": "gql-gen --config graphql/codegen.yml --watch"

The codegen.yml has the schema and document configuration. At first, I was confusing about these two terms. The documentation is dry on the differentiation. The schema configuration is about where to get the GraphQL schema, this is the downloaded unified GraphQL schema from the server. The document is which TypeScript file to analyze (could be JavaScript file as well).

schema: "./graphql/**/*.graphql"
documents: "./src/**/*.+(tsx|ts)"
overwrite: true
generates:
  ./src/autogenerated/octoolstypes.ts:
    config: {}
    plugins:
      - "typescript-common"
      - "typescript-client"
require: ['ts-node/register']

It uses few plugins, hence you need to get the NPM packages accordingly.

"graphql-code-generator": "0.16.0",
"graphql-codegen-add": "0.16.0",
"graphql-codegen-typescript-client": "0.16.0",
"graphql-codegen-typescript-common": "0.16.0",
"graphql-codegen-typescript-server": "0.16.0"

The graphqlcodegen will check and generate the code. Unfortunately, it is slow. Even on a small code base, the process can take 10-15 seconds. Nonetheless, you have your TypeScript type generated for you and it will adapt with the backend (GraphQL server) changes.

Conclusion

Having the type generating automatically from the backend is fascinating and is efficient. If your business domain is rich in quantity of entities (interfaces) and if many of them have several fields and complex interconnection than having the type generated instead of typing it manually is a relief.

Related GraphQL Articles

TypeScript with Strong Typed Action when using useReducer of React Hooks

The technic I will demonstrate in this article comes from what I was using with the traditional React and Redux. Now, with React Hooks we do not need to use Redux anymore but the same principles exist with the hook useReducer. I have witnessed many people struggling using TypeScript and Redux because they are passing strings around instead of a string literal. Often, the struggle I hear is around the boilerplate required as well as it is not strongly typed. Let’s try to make it as simple as possible and strongly typed in term of action name and action payload

Code

If you want to play around with what I will present, you can jump into the code sandbox available under this paragraph. However, keep in mind that you will not see the benefit of having Intellisense showing available actions and the security of working in VsCode where it will warn you if you are passing something of the wrong type — this is a limitation of the online sandbox tool. The demonstration has many files, I suggest you click “Open in Editor” and click the hamburger menu to navigate between files.

Configuring the Actions

The first step is to get some types. Once you have that code in your project, you will be good to go without touching it. I am posting the code and will explain what it does.

/**
 * Create an action that has a strongly typed string literal name with a strongly typed payload
 */
export function createActionPayload<TypeAction, TypePayload>(
  actionType: TypeAction
): (payload: TypePayload) => ActionsWithPayload<TypeAction, TypePayload> {
  return (p: TypePayload): ActionsWithPayload<TypeAction, TypePayload> => {
    return {
      payload: p,
      type: actionType
    };
  };
}

/**
 * Create an action with no payload
 */
export function createAction<TypeAction>(
  actionType: TypeAction
): () => ActionsWithoutPayload<TypeAction> {
  return (): ActionsWithoutPayload<TypeAction> => {
    return {
      type: actionType
    };
  };
}
/**
 * Create an action with a payload
 */
export interface ActionsWithPayload<TypeAction, TypePayload> {
  type: TypeAction;
  payload: TypePayload;
}

/**
 * Create an action that does not have a payload
 */
export interface ActionsWithoutPayload<TypeAction> {
  type: TypeAction;
}

/**
 * A very general type that means to be "an object with a many field created with createActionPayload and createAction
 */
interface ActionCreatorsMapObject {
  [key: string]: (
    ...args: any[]
  ) => ActionsWithPayload<any, any> | ActionsWithoutPayload<any>;
}

/**
 * Use this Type to merge several action object that has field created with createActionPayload or createAction
 * E.g. type ReducerWithActionFromTwoObjects = ActionsUnion<typeof ActionsObject1 &amp; typeof ActionsObject2>;
 */
export type ActionsUnion<A extends ActionCreatorsMapObject> = ReturnType<
  A[keyof A]
>;

The first function uses a type named ActionsWithPayload. The function must be used when you create a new action that carry a payload. It will take two generics type. The former is the string literal of your type: a unique identifier for your action. The latter is the type of the payload. For example, you can set a field of an entity, like the name of a person, by using the following code.

setName: createActionPayload<typeof ACTION_SET_NAME, string>(ACTION_SET_NAME)

The setName is the strongly typed function of the action that you use to dispatch later on. It is linked to the specific string literal ACTION_SET_NAME (unique identifier) and the payload that can be passed to the action is only a string. You invoke the action by calling that function with the payload that you desire:

dispatch(setName("MyNewNameHere"));

The return of the function createActionPayload is an object with the payload and the type — both strongly typed. It allows to have in your reducer a comparison on the type which is unique because it is not a string — but a string literal type. To accomplish this feat, you must define one type per action. That is why, in your reducer file (or the file you want to store all your actions) you must defined a one line per action

export const ACTION_INCREASE_COUNT = "ACTION_INCREASE_COUNT";
export const ACTION_SET_NAME = "ACTION_SET_NAME";

The createActionPayload has also a sibling function createAction that does not take any payload. It works in a similar fashion which is that the type of the action is a unique string literal, but that time without a payload.

To recap what we need to far: first, we need to create a constant that is a string literal that will be used as a unique identifier of the action. Second, we need to create a function that has a payload strongly typed by the action’s type. To tidy up everything, I usually group all common action in a single object.

export const AppActions = {
  increaseCount: createAction<typeof ACTION_INCREASE_COUNT>(
    ACTION_INCREASE_COUNT
  ),
  setName: createActionPayload<typeof ACTION_SET_NAME, string>(ACTION_SET_NAME)
};

It changes slightly how to invoke the action which is clearer. It “namespaces” the action.

dispatch(setName("MyNewNameHere")); // Before
dispatch(AppActions.setName("MyNewNameHere")); // After

Reducer

The reducer is exactly like with Redux, it is a function that takes a state and an action. However, our actions will be constrained to the group of action we allow for the reducer.

export function appReducer(
  state: AppReducerState,
  action: AcceptedActions
): AppReducerState {
// ... 
}

Because we have a strongly typed function per action, we can now define a collection of allowed actions. It helps when you have several reducers in an application to limit the scope of what is expected. If you are tidying the action in an object as proposed, you can do:

export type AcceptedActions = ActionsUnion<typeof AppActions>;

The AcceptedActions type is from the type you add in the ActionsUnion. It means you can add several group of action if you desire with the following syntax.

ActionsUnion<typeof ActionsObject1 &amp; typeof ActionsObject2>;

Here is the complete reducer, like any reducer that you are used to code. However, the switch case only accept cases with the name that are from the AcceptedState which clarify what is possible or not to reduce.

export function appReducer(
  state: AppReducerState,
  action: AcceptedActions
): AppReducerState {
  switch (action.type) {
    case ACTION_INCREASE_COUNT:
      return {
        ...state,
        clickCount: state.clickCount + 1
      };
    case ACTION_SET_NAME:
      return {
        ...state,
        activeEntity: { ...state.activeEntity, ...{ name: action.payload } }
      };
  }
  return state;
}

React Hooks useReducer

The last piece of the puzzle is how to consume the data from the reducer’s state and how to mutate the value. The useReducer function is a React Hooks that take the reducer function and the initial state as parameter. It returns the state and the dispatcher funciton.

const [state, dispatch] = useReducer(appReducer, appState);

To read the value of the state, it is a matter to use the variable state. Because the state is strongly typed, you will get your IDE support as well as static validation from TypeScript. Same for the invocation.

      <button
        onClick={() => {
          dispatch(AppActions.increaseCount());
        }}
      >{`Increase State Count ${state.clickCount}`}</button>

The dispatch requires a function. We reuse the tidy object to select the action. The object is strongly typed, hence when typing you get a nice autocompletion of what action can be dispatched. You avoid any potential mistake of using a variable that is not supported by the reducer. In that example, there is no payload, but the following example shows a strongly typed action with a strongly typed argument.

      <button
        onClick={() => {
          dispatch(AppActions.setName("test"));
        }}
      >

Conclusion

With about 50 lines of TypeScript, you get few utility functions and types to handle React Hooks’s reducer with TypeScript in a pleasant way. As a developer, a new action is a matter of adding a line to uniquely identifier the action, and to define a one-line function to associate the action to a payload type. The reducer is strongly typed, the dispatch of action is also strongly typed. The solution scales well with multiple reducers, it works well with clarifying what can be dispatched and ensure consistency within the application by having a design that group actions of a similar domain together.

GraphQL Resolvers with Apollo

In this article, we will discuss about two topics that concern resolvers and performance. So far, and by default, everytime a resolver is invoked, this one execute its actions which is mostly be to fetch the data. The problem is that in a graph there is potentially redundant information that will be fetched several time causing performance issue.

For example, a query on an object that is cyclic with cyclic information will cause duplication of call. Imagine querying for obj1->obj2->obj1->obj2.

The problem becomes gargantuan with an array of object. Imagine that you have a single query for each type that is in a big array, you would perform many hundred or thousand of requests while in practice you probably would have use a special endpoint that return a batch of all the information.

The good news is that GraphQL has the concept of resolving at many levels. It is possible to resolve at the root level, which mean directly at the query level. But, alos at any edge which is great for an edge into an array of object or a heavy object that require special need. How, it is possible to resolve at the field level which can also be interesting in the case of a particular field that needs to be tackled differently of its general type.

Three different resolvers: Query, Edges and Fields

The two concepts we will investigate is “look-ahead” and “batching”. The look ahead is the idea of looking in the query schema and performing chirurgical analysis of what is requested. Batching is the of collecting all the desired data to fetch and fetch it once we are done traversing the tree. It means that if in the graph we have several times the same entity to query that we will only do it once — at the end. From these two summaries, it is clear that one is to optimize the query in term of figuring out which would be the best while the second is to avoid redundant calls. The former can help for avoiding calling several endpoints by redirecting the logic into a single endpoint while the latter removes querying the same element.

Look-ahead

A parent children is the common scenario. Imagine a parent who has many children. GraphQL by default will call the resolver for the parent and then will call a single resolver by children. If you have the resolver of the parent fetching the parent data (1 HTTP request) and then one fetch at each child (1 HTTP request multiplied by the number of children) it can become not performant. Even if the GraphQL is connected directly to a database, it would not be performant on a big list of children. The database scenario is often easier to visualize. Instead of making several SELECT statement with a WHERE clause that specify a single child ID, we would do a SELECT statement with a IN clause that specify the array of IDs. That way, it would return a single query response with many rows. In REST, if you have an endpoint that allows the parent to expand the children, you can use that endpoint instead of the one that only return the immediate parent attribute.

In GraphQL, you can peek at what is being queried. The look-ahead notion is the exploration of what the user specified in the query. The information is available in the fourth parameter of the query. The parameter’s type is “GraphQLResolveInfo”. You can use a NPM package named “graphQLFields” that will give you an easy way to access the information.

const fields = graphQLFields(graphQLResolveInfo);

Once you have extracted all the fields, you can check if the children node is being requested. If not, you can fetch the parent information without the additional payload (SELECT directly the ID without further data from children).

 if (fields.sites !== undefined){
    // Perform a more exhaustive query that will save us many small request
}

There is still one issue with the look-ahead: the children resolver is still called and will still perform the request. How can we notify the children that we already have everything we need in a clean way? This is where batching come in.

Batching

Batching is doing two things: cache and batch many ids. The whole idea is that instead of calling directly your SQL or REST endpoints, you call the DataLoader. It is a layer of abstraction that will check if we already have a promise for the key requested. If so, it returns the existing promise. The promise can be already resolved which would be very fast. The DataLoader library is a NPM package that has its own TypeScript definition file which is convenient if you are writing your code in TypeScript.

Naturally, the DataLoader is taking an array of the key. Even if you want to request for a single element, the DataLoader will presume that you query for a collection. I will not go in this article about pattern that you can use other than mentioning that you could look at the number of ids passed in the DataLoader and take a smart decision about how to fetch the data. Worth mentioning, the load function of the DataLoader that is needed to get the information from the cache or the code inside the data loader (to fetch) can be invoked multiple times. The DataLoader will coalesce all singular loads which occur within a single tick and then call your batch loading function.

An effective way to work with DataLoader is to have a single DataLoader by way to query the information. For example, if you query a “parent” entity by id, you would have a DataLoader for “parent” by “id”. You will have one for “parent” by “name” and one for “child” by “id”, etc. The separation might sound redundant but a single GraphQL query does not ask for many entities in a different way, hence does not duplicate much.

A good way to keep everything tidy up is to define a class into which we can inject the current user’s request. It gives all the security information like any authentication bearer token that the fetching code might need. The class trickle down the context information (user’s HTTP request) by having the request passed in its constructor parameter down to the service that will fetch the data. In the following code, you can see the pattern.

export class DataLoaders {
    private dataSources: GraphQLCustomDataSources;
    public getParentByParentId: DataLoader<number, Parent>;
    public getChildByChildId: DataLoader<number, Child>;
    public getChildrenByParentId: DataLoader<number, Child[]>;

    public constructor(requestTyped: IUserRequest) {
        this.dataSources = {
            sourceApi1: new Api1HttpService(requestTyped),
            sourceApi2: new Api2HttpService(requestTyped)
        };

        this.getParentByParentId = new DataLoader<number, Cache[]>(parentIds => {
            const proms: Promise<Parent[]>[] = [];
            for (let i = 0; i < parentIds.length; i++) {
                proms.push(this.dataSource.sourceApi1.getParent(parentIds[i]));
            }
            return Promise.all(proms);
        });

        // And so on for each DataLoader...

    }
}

The code above is a short version of what it can be with two entities: Parent and Child. In reality, you would have way more DataLoader and might want to breakdown each detail into a separated file and use the DataLoaders class as a facade to all the logic. The goal here is to have a single point of initialization to get the HTTP request passed down to the implementation of the data source.

Still, there is an issue. We are caching the DataLoader of the Parent entity, not the Child entity. It means that when the GraphQL traverse and invokes the children resolver, that this one will call the DataLoader that request the child information by child id, not by parent ID. There are many patterns. You could invoke the parent DataLoader and check if the data is already present. You can also have the parent DataLoader primes the child DataLoader. Priming the data means to set in another cache the data. The following code can be added to the DataLoader previously built. Now, the GraphQL invokes the DataLoader of the parent, get the data and populate the parent’s cache. Because it has the information about the children, it loops the collection and primes the child’s DataLoader as well. The traversal continues and the child’s resolver calls the child’s DataLoader that has a promise resolved with the child data.

children.forEach(c => {
      this.getChildByChildId.prime(c.id, c);
});

From there, you instantiate the class once in the Apollo’s server configuration. The instantiation will occur at every request, hence no data is mixed between users.

async function apolloServerConfig() {
    const serverConfig: ApolloServerConfig = {
        schema: schemas,
        context: (context: GraphQLCustomResolversContext) => {
             const newContext: GraphQLCustomContext = {
                loaders: new DataLoaders(requestTyped)
            };
            return newContext;
        },
    // ...
    }
}

Summary

The DataLoader library is useful to cache data during a single request when GraphQL is traversing the tree. A parent node can look-ahead and load in batch information reducing the number of future requests. The DataLoader library cache the result for each DataLoader. In the code presented, the DataLoader was filling up the parent loader which might not be useful in the situation but by priming the child’s DataLoader jettisoned all costly subsequent in the child’s resolver.

Related GraphQL Articles

How to setup a TypeScript, NodeJS, Express Apollo Server to easy debugging with VsCode

There is a lot of keyword in the title but this is not a clickbait, we will setup without too much burden a simple configuration that will allow Visual Studio Code (VsCode) to hook into a GraphQL installation. The idea is that everytime a TypeScript file is saved that automatically the file is transpiled into JavaScript and to have Node reboot. The solution I propose can do the transpilation, the schema transportation and the restart of NodeJS under 2 seconds.

NPM

The first step is to get some NPM packages. The first one is named concurrently which will allow from a single line, a single NPM command to execute multiple commands. This is required to have TypeScript in watch mode, having a file watcher for the GraphQL schemas and restarting node if any of the previous two changes. The second is the package cpx which can watch for file and copy them if something changes. The third is TypeScript that will watch all TypeScript file for changes and build into the output folder. The fourth package is nodemon that monitor changes in file. If a file change, it restart Node.

"concurrently": "^4.1.0",
"cpx": "^1.5.0",
"typescript": "^3.2.2",
"nodemon": "^1.18.8"

Then few NPM scripts are required.

"dev": "concurrently \"tsc -w\" \"npm run watchgraphql\" \"nodemon build/dist/index.js\"",
"debug": "concurrently \"tsc -w\" \"npm run watchgraphql\" \"nodemon --inspect build/dist/index.js\"",
"watchgraphql": "cpx 'src/graphql/schemas/**/*.graphql' build/dist/graphql/schemas/ -w -v"

There are two main scripts. The dev and debug. I mostly run the second one because it does the same as the first one with the addition of opening a port for VsCode to connect to debug the NodeJS (Express) server. What it goes is to start concurrently TypeScript in watch mode (-w), run the watchgraphql and nodemon to watch every file (produced JavaScript and GraphQL schema files. The GraphQL’s schemas have there own extension “.graphql” and are not moved like TypeScript during the transpilation. Hence, it requires a separate process to move the file when we edit the file.

Visual Studio Code

Finally, within Visual Studio you need to create a debug launch configuration. The creation occurs in the fourth button of the menu, the one with a bug. It is possible to select “Add Configuration” in the dropdown to create a new debugging configuration. Here is the one I am using:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Attach to node",
            "type": "node",
            "request": "attach",
            "restart": true,
            "port": 9229
        }
    ]
}

It will attach to an existing instance. It means that if you want to debug the startup of the NodeJS server that it does not work. You will need to change the way to avoid using nodemon and to have the VsCode debugger starting the NodeJS server. It is not a use case that I need, hence I do not have it configured.

Once you have these scripts in place and the VsCode configuration saved. You can click the play button or F5 to start debugging. It takes about 1-2 seconds to hook to the process. Any breakpoint you have set will stop the process and gives you time to explore the variables. If you do a change during the debug, NodeJS will restart and the debugging will stop and restart as well.

HTTP Request Debugging

I am using Axios, but other libraries allow also to shim a proxy to inspect HTTP request and response. It is very valuable when debugging an Apollo GraphQL server because you cannot do like with a web application and use Chrome’s network tab. A trick with Axios is when you configure the AxiosRequestConfig to set a proxy in the HTTP header of the request that point to your computer.

config.proxy = {
    host: "127.0.0.1",
    port: 5555
};

Then, installing a tool like Postman at the specified port is enough to receive every request with the proper HTTP headers in place.

Summary

I am far from being an expert concerning developing server side application with NodeJS. I was impressed of the quick result. Within an hour, I had a development environment that was efficient to develop and to debug. The experience of debugging directly in TypeScript is awesome and to see every request and response swimming through the proxy tool is priceless when it is the time to understand what is coming out and in the GraphQL’s resolvers.

Some other GraphQL articles

Apollo GraphQL Resolvers and Data Source separation

Resolvers can perform asynchronous call to fetch data. Using the specific implementation to perform the fetch in the resolver cause the resolver to have high-coupling into the technology to access the data but also increase the complexity of the resolver by boosting the size of each function with the request’s details. Apollo’s resolver allows to pass from the Apollo server’s configuration a set of data sources that can be used down the line by every resolver.

Resolvers and DataSource Relationship

Similar to resolvers, datasources is a member is defined in the ApolloServerConfig. The member is a function that returns a map (dictionary) of data sources. The datasources is strongly typed as “DataSrouces<T>” where T is your custom context.

dataSources: () => {
    const dataSources: DataSources<GraphQLCustomContext> = {
        dataSourceName1: new MyDataSource1()
    };
    return dataSources;
},

I create one data source per domain because all Rest and gRPC service are already divided by business domain. However, there is no conscribed way to split the data sources. Each data source is class that eventually must inherit extends DataSource<T> where T is the custom context you have defined for your GraphQL server. 

In the Netflix Open Connect GraphQL, I decided to have all my REST data source inherit a generic base class that handles all Axios code. The REST class inherits the DataSource from “apollodatasource” package. The REST encapsulate the Axios package which can be changed later for something else without having to touch resolvers.

Data Sources and Services

It worth pointing that a single data source can use more than a single service. A data source class has many functions for different requests and each of the function can request to one or many services.

Resolvers are now getting access to the data sources by reaching the context which is the third parameters.

export const bookResolversMap = {
    Query: {
        book: async (source: null, args: { bookId: number }, context: GraphQLCustomResolversContext, graphQLResolveInfo: GraphQLResolveInfo) => {
            try {
                return await context.dataSources.bookService.getBook(args.bookId);
            } catch (e) {
                console.error(e);
            }
        }
    }
};

One question might rises. How is the context having the data source? A keen observer might have spotted that resolvers are not using the type GraphQLCustomResolversContext for the context instead of the GraphQLCustomContext has in all the previous article of this series. The type remains like the original context for everywhere in the application, except for the resolvers. The data sources are injected into the context by Apollo. The TypeScript types for GraphQL context is now in three interfaces.  A first one that contains all the data source, one that contain the actual context which we previously defined to contain user’s information. Finally, a third one that has the data source and extends the custom context.

export interface GraphQLCustomDataSources {
    dataSource1: MyDataSource1;
}

export interface GraphQLCustomContext {
    userRequest: IUserRequest;
}

export interface GraphQLCustomResolversContext extends GraphQLCustomContext {
    dataSources: GraphQLCustomDataSources;
}

Summary

In this article, we saw how to move a piece around to have a cleaner architecture. The separation of concern allows changing piece without potentially breaking other pieces of code. The division of the task increases the easiness to create unit tests. The little job that each part must conduct simplify the understanding of the code and increase the reusability. In the next article, I’ll present how to debug the NodeJS server, Apollo and all the part we already have a setup which will simplify diagnostic when something is going south.

My Other GraphQL Posts