Accessing your local machine from a Docker container

A small entry about Docker. I am using Docker mostly in development to have one Docker per web application I am running. It gives me the advantage to have different instances of Apache running that are isolated. A few time ago, I wanted to perform an HTTP request from inside the Docker container back to my development machine — I could not. I was hitting 503.

Docker’s localhost is not my machine localhost. After some research, I found that using the DNS docker.for.mac.host.internal was the way to access my developer machine. It works for a MacOs.

How to Curl a GraphQL API?

In the last few months, I have been implementing a GraphQL server in TypeScript and NodeJS using Apollo. You can build your query with the playground and see the result immediately. At the top, a “Curl” button generates a Curl command. However, it writes the command with many options that are not required.

The generated command line has “–compressed” and “–data-binary” which might be fine for few people but in some case, these options were not available. I figure out that you do not need to provide them and still be able to invoke the GraphQL server.

curl 'http://retracted.net/playground' \ 
  -H 'Accept-Encoding: gzip, deflate, br' \
  -H 'Content-Type: application/json' \ 
  -H 'Accept: application/json' \
  -H 'Connection: keep-alive' \
  -H 'DNT: 1' \
  -H 'Origin: http://retracted.net' \
  --data-binary '{"query":"{\n  org(orgId: 0) {\n    nameLong,\n    nameShort\n  }\n}\n"}' \
  --compressed

The generated Curl command line for GraphQL has many headers that can be removed. In my case, I needed to add the authorization header because the service is private.

curl \
  -X POST \
  -H "Content-Type: application/json" \
  -H "authorization: Bearer xxx" \
  --data '{"query":"{\n  org(orgId: 0) {\n    nameLong,\n    nameShort\n  }\n}\n"}' \
  http://retracted.net/api

However, even with the additional header, the command is more straightforward. Instead of requesting the data with “–data-binary”, it is possible to query with “–data”. The compression can be removed if the “accept-encoding” is not specified. The content we will receive is of JSON type, hence we need to specify the “content-type”

In conclusion, this was a short essay on how to use Curl with GraphQL. It can be handy if you have internal tools that mimic Curl but without the more advanced options like compression or binary data.

Configuring Apollo Playground and API on two different URL

By default, Apollo GraphQL middleware install the server in Express under the same URL. If you use the URL in the browser (GET), the playground loads. If you use the URL as a POST the data is returned. The website and the API are both using the same URL. It is problematic if you want the playground to use a particular authentication system (e.g., web-based) and the API to use an other (e.g., token approach). In this article, I will present a simple way to have the web playground and the API over two different URLs.

The idea is to start two Apollo middleware and route them with different options. The playground can be even simpler that what I am presenting. I am adding a few playground settings. Because I am using TypeScript, all the fields are marked to be required, hence I am explicitly specifying the value for each. The “request.credentials” is required with the authentication mechanism under which I am developer the GraphQL.

app.use(playgroundEndpoint, authorizeUserMiddleware);
const playgroundServer = new ApolloServer({
 schema: schemas,
        engine: true,
        context: (context: GraphQLCustomResolversContext) => {
            const requestTyped = (context as any).req as IUserRequest;
            const newContext: GraphQLCustomContext = {
                loaders: new DataLoaders(requestTyped)
            };
            return newContext;
        },
        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"
            }
        }
});
playgroundServer.applyMiddleware({ app, path: playgroundEndpoint, cors: true });

The second configuration is for the API. The arrangement is slightly more simple. The reason is that the middleware needs to disable the playground and nothing else.

app.use(apiEndpoint, authorizeUserMiddleware);
const apiServer = new ApolloServer({
    schema: schemas,
    context: (context: GraphQLCustomResolversContext) => {
        const requestTyped = (context as any).req as IUserRequest;
        const newContext: GraphQLCustomContext = {
            loaders: new DataLoaders(requestTyped)
        };
        return newContext;
    },
    playground: false,
    introspection: false
});
apiServer.applyMiddleware({ app, path: apiEndpoint, cors: true });

In both cases, I set a custom “authorizeUserMiddleware” that read the user credential and figure out what the user can do or not. The important parameters to disable are the playground, the introspection

The code that is hooking Apollo middleware into Express server next were you define the Express variable. From there, you need to start the server and both URLs will be served.

Related GraphQL Post

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.