Optimizing Apollo Operations - GraphQL Code Generator & Relay Compiler
Tags: graphql, codegen, relay
Published: 2021-07-29 09:00:26

> This article was published on Monday, July 15, 2019 by [Laurin Quast](https://twitter.com/n1rual) @ [The Guild Blog](https://the-guild.dev/)

As a TypeScript developer, I love working with the
[GraphQL Code Generator](https://graphql-code-generator.com). It is a very powerful code generation
tool for both your frontend and your backend. Instead of having to manually create types for
something your GraphQL Schema already provides, due to its type-safe nature, you can actually focus
on building the product.Currently, my favorite library for querying GraphQL backends is `react-apollo`. Supercharged with
the GraphQL Code Generator the library unleashes an almost unfair productivity boost compared to
every other data fetching stack I have used in my career as a software developer.Of course, I have heard of other libraries before, but until recently I never had the motivation of
actually using another one.This, however, changed after watching the
[F8 presentation about the Facebook.com rewrite](https://developers.facebook.com/videos/2019/building-the-new-facebookcom-with-react-graphql-and-relay).I totally fell in love with the "component specify their data requirements approach", which is
implemented by utilizing GraphQL Fragments.**As an Apollo user, I have used fragments before, but not in the same way Relay does.**Let's take a look at the following Fragment:```graphql
fragment UserAvatar on User {
  id
  avatar(width: 10, height: 10) {
    id
    url
  }
}
```How would you reuse this fragment with different values for the `width` and `height` arguments?Previously there have been two ways I would have tackled this:**1. Write a new fragment with different parameters**Well, just creating a new document for our avatar won't really solve the reusability issue.**2. Use variables and rely on the query to have those defined**Actually, you can already use variables inside fragments. We just need to ensure that the query that
uses the fragment also has those variables in the variable definition.Fragment Definition:```graphql
fragment UserAvatar on User {
  id
  avatar(width: $width, height: $height) {
    id
    url
  }
}
```Query Definition:```graphql
query ProfileQuery($width: Int!, $height: Int!) {
  me {
    ...UserAvatar
  }
}
```However, we now rely on having those parameters provided in each query that uses that fragment.This does not really make the fragment reusable. Imagine having a profile query of a with a friend
list. The profile picture should be bigger than the ones of the friends.```graphql
query ProfileQuery($width: Int!, $height: Int!) {
  me {
    id
    ...UserAvatar
    friends(first: 10) {
      id
      ...UserAvatar
    }
  }
}
```It is basically impossible to use a different width and height for the second usage of the fragment
in that query.Furthermore, when using different fragments you have to be really careful with your variable names,
because of variable name clashes.Given those limitations, it is pretty obvious that this “solution” does not scale well.**I have experienced this limitation before and I am amazed how Relay solves it**Relay simply uses custom GraphQL directives to address this issue.**Defining Fragment Variables with `@argumentDefinitions`**```graphql
fragment UserAvatar on User @argumentDefinitions(
  width: { type: “Int”, defaultValue: 10 },
  height: { type: “Int”, defaultValue: 10 }
) {
  id
  avatar(width: $width, height: $height) {
    id
    url
  }
}
```Providing Fragment Variables with `@arguments````graphql
query ProfileQuery {
  me {
    id
    ...UserAvatar @arguments(height: 20, width: 20)
    friends(first: 10) {
      id
      ...UserAvatar # fallback to defaultValue here
    }
  }
}
```Pretty powerful, right?Unfortunately, you cannot simply use those fragments with your existing GraphQL Server.
`@argumentDefinitions` and `@arguments` are some custom directives that need to be understood by the
server in order to process them.However, instead of implementing those directives on the serverside Relay went another route. The
`relay-compiler` removes those directives at build time. That means after our query has been
processed it looks something like the following:```graphql
query ProfileQuery {
  me {
    id
    ... on User {
      id
      avatar(width: 20, height: 20) {
        id
        url
      }
    }
    friends(first: 10) {
      id
      ... on User {
        id
        avatar(width: 10, height: 10) {
          id
          url
        }
      }
    }
  }
}
```Pretty neat. This allows the query the be accepted by every GraphQL server (that, of course,
provides the correct schema), without relying on those custom directives.**The `relay-compiler` is awesome!**It comes with a lot more transforms. Some of those are specific to the `relay-runtime` (which as the
name says is executed in the browser of the user like react-apollo), but others are definitely also
beneficial to non-relay users.Besides the so-called `RelayApplyFragmentArgumentTransform` there is a bunch of more useful stuff.E.g. the `FlattenTransform` can improve our query even more:```graphql
query ProfileQuery {
  me {
    id
    avatar(width: 20, height: 20) {
      id
      url
    }
    friends(first: 10) {
      id
      avatar(width: 10, height: 10) {
        id
        url
      }
    }
  }
}
```I also built a [relay-compiler REPL](https://relay-compiler-repl.netlify.com) (use it for convincing
your team 😉).Of course, you can also read more about those in the
[Official Relay Documentation](https://relay.dev/docs/en/compiler-architecture#transforms).Especially on big queries, that utilize many fragments, those transforms can drastically reduce the
query payload size, resulting in faster response times. For developers that cannot use persisted
queries (because they do not own the server), this is a must-have!**After having seen all those benefits that Relay users can leverage I was convinced that I want to
use those as well.**But unfortunately, I was still working with Apollo. 😅What if there was a way to use the `relay-compiler` with Apollo?I was already generating code with the GraphQL Code Generator.**So maybe we can transform the queries before the GraphQL Code Generator outputs the generated
code?**{% twitter 1139679080582930434 %}After some investigation in the Relay and the GraphQL Code Generator codebase, I had a working
version ready for use.Given those Relay superpowers, I now feel even more productive.For those curious, I also created a sample project:
[TodoMVC Apollo](https://github.com/n1ru4l/codegen-relay-transform-experiments/tree/master/packages/todo-app-example)
(Converted from the Relay Examples).Of course, you can also take a look at (and use!) the
[Relay Operation Optimizer](https://graphql-tools.com/docs/relay-operation-optimizer)Example configuration for a react-apollo project:**codegen.yml**```yaml
overwrite: true
schema: "schema.graphql"
generates:
  src/generated-types.tsx:
    documents: "src/documents/**/*.graphql"
    config:
      skipDocumentsValidation: true
      flattenGeneratedTypes: true
    plugins:
      - "typescript"
      — "typescript-operations"
      — "typescript-react-apollo"
```**I hope you enjoyed reading this! Are you already using Relay? Do you feel like you want to add the
relay-compiler into your GraphQL toolbox?**Also, feel free to follow me on these platforms, if you enjoyed this article I ensure you that a lot
more awesome content will follow. I write about JavaScript, Node, React and GraphQL.*   [Dev.to](https://dev.to/n1ru4l)
*   [Medium](https://medium.com/n1ru4l)
*   [Twitter](https://twitter.com/n1rual)
*   [Github](https://github.com/n1ru4l)Have an awesome and productive day!