Skip to content

Codegen collaboration with Apollo Codegen and GraphQL Code Generator #2053

@dotansimha

Description

@dotansimha

Hello Apollo team and Apollo Codegen users!

I’m Dotan and I’ve created a library called graphql-code-generator, which we maintain for the past 4 years that aims to solve some of the same issues as Apollo Codegen.

While working with a very large codebase of one of our new clients that was using Apollo Codegen, we’ve seen that the support for Apollo Codegen and it’s issues has slowed down in recent years, (looking at the history of the apollo-codegen-core, apollo-codegen-flow and the apollo-codegen-typescript libraries, it looks like the last meaningful workload was made around August 2018) and we wanted to offer our help!

On the following issue I will try to describe everything I can about the 2 codegens, in order to collaborate together on two possible paths:

  1. Integrate graphql-code-generator into Apollo Codegen while keeping Apollo Codegen as a wrapper (we don’t care about credit :) )
  2. An easy path for Apollo Codegen users to migrate to simply using graphql-code-generator

At the end, the goal here is to share all the work we’ve done in graphql-code-generator with Apollo and it’s community, in order to help Apollo in whatever way Apollo would see fit.

I will write about the difference between the codegens as they are today, two possible migration paths and a list of all open issues on Apollo Codegen that could be addressed by this collaboration.

We would love any feedback, from the great people at Apollo and it’s amazing community members!

We are currently just talking about the Typescript and Flow generators, as @designatednerd has been doing amazing work on the Swift codegen so no need for our help there!
(But we are still happy to help and collaborate there if needed, as we have Swift codegen plugins maintained by our community).

Ok here we go:

We’ve reviewed the implementation of Apollo Codegen and reviewed all open issues related to codegen on this repo and came up with a possible plan to move forward we would love your feedback on.

There are some differences in the generated output of the two generators.
We’ll explain here the differences in philosophies but we’ve also created a configuration for graphql-code-generator that generates similar output to Apollo Codegen and supports all the flag options of the Apollo CLI in order to make the switch easy and for you to have the option to gradually adopt our best practices or to simply stick with your own.

It is also a good time to kick start this collaborative initiative as we’ve started planning our next major version, GraphQL Code Generator 2.0, and would be great to get Apollo and the Apollo community be an active part in shaping that next release!
(Including the new TypedDocumentNode plugin)

First, what is GraphQL Codegen and what are the Differences compared to Apollo Codegen

Here we try to describe the current differences between the tools, even though they can be almost identical with the right configuration in GraphQL Code Generator

  • Output
    • Apollo codegen yields multiple files - a file per input file, and GraphQL Codegen prefers a single file to be generated
    • Multiple files are harder to maintain and are spread through the entire codebase, and generated output should always take into account the imports (which are not always predictable, especially in large/complex codebases, or monorepos).
    • Performance - We’ve seen users ask for multiple files because they thought it would give them better build performance. In every single case, we’ve demonstrated to them that a single file with the right configurations is much faster
      It’s still possible to generate multiple files (with a codegen preset) if you wish to.
  • Intermediate types
    • GraphQL Codegen dropped default support for generating types of nested selection sets. We prefer to let developers have the ability to do that with GraphQL fragments.
      TypeScript (and Flow) allow you to access nested types easily and alias it if you wish to.
    • GraphQL Codegen still supports generating intermediate types, but as a general approach, we recommend you not to do that (harder to maintain, causes mismatch issues, doesn’t scale with flexible configurations)
  • Yaml config
    • One of the goals of GraphQL Codegen is to be flexible as possible. That means, you can easily customize the output to match your needs, and especially makes it simpler to integrate with existing codebases.
    • You can also use it programmatically, and have low-level over the input and output. You can also configure it with JSON or JavaScript if you don’t like YAML.
  • Loaders
    • Codegen automatically loads your schema from any source (file, local file, remote file, code files, GitHub, Apollo Graph Manager and more).
    • GraphQL Codegen also knows how to extract and parse your GraphQL operations from your components code.
    • You can easily customize the way you load your schema and your operations.
  • Plugins
    • Our community has over 100 plugins, for various languages, platforms and frameworks.
    • Creating your own plugin is as simple as creating a local file in your repository. Codegen will pick it and integrate your custom plugin with other plugins.
  • More than just basic types
    • Resolvers signature - codegen allows you to generate type-safe resolvers signature (for TS, Flow and Java). You can also bring your own models types for types and context, and integrate it within the generated types. It will fully type your resolvers’ parent value, arguments, context and return value.
    • Ready-to-use code - ensures better usage in large teams. You can generate fully-typed React-Apollo Hooks, Apollo-Angular Services for wrapping data fetching, Vue-Apollo data components and more.
    • Fragment matcher - GraphQL Codegen can generate the fragments-matcher or possibleTypes object required by Apollo-Client.
    • Precompiled DocumentNode - codegen can pre-compile GraphQL operations into DocumentNode and eliminate the need for graphql-tag.
    • Introspection or schema-ast - Codegen has some abstractions for GraphQL and GraphQL-Tools, in order to make it simpler for your to create GraphQL introspection file, or even for merging schemas and printing it as GraphQL SDL.
  • Activity on the repo
    • We encourage the community to share all ideas, concepts and plugins they need. We aim to allow codegen to be flexible enough and simplify it’s integration in all codebases.
    • We aim to release a new version with dependencies updates and bug fixes every week (and each change we do get it’s own alpha release automatically, so no need to wait for the new release in order to test new features or bug fixes). This has been that case for about 4 years and we don’t have any intention of stopping.
  • Integration with other tools
    • Federation - you can integrate your Apollo Federation backend and generate resolvers signatures based on the capabilities of each service.
    • More integrations - TypeGraphQL, Apollo Local State, Gatsby (and more).

Possible Migration Guide

As an Apollo Codegen user that wishes to migrate to GraphQL-Codegen, you have 2 options - either to use GraphQL Codegen and have a very similar output (with zero to minimal code changes), or adjust your project to the concepts of GraphQL Codegen. You should choose according to the size of your codebase and it’s complexity.

Option 1: Migrate to GraphQL-Codegen concepts

One of the major differences is the output itself - codegen aims to generate a single file with all the types. It’s easier for the IDE and for the TypeScript compiler.

The equivalent for TypeScript types based on GraphQL schema and operations, is the following configuration:

schema: PATH_OR_URL_TO_SCHEMA
documents: GLOB_EXPRESSION_FOR_OPERATIONS
generates:
  ./src/types.ts:
    plugins:
      - typescript
      - typescript-operations

You can start with it, and gradually extend it with more plugins and more features, according to your needs.

Option 2: Have the same output

This solution will leverage more complex codegen features and configurations, in order to create output that will be compatible with the same file-names and identifiers names that Apollo-Codegen creates today.

The following configuration file will help you:

# The value you are using today for `client:download-schema` - no need to download, store and then
# use it - codegen does that automatically.
schema:
  - PATH_OR_URL_TO_SCHEMA
documents:
  - GLOB_EXPRESSION_FOR_OPERATIONS # Equivalent for `--includes` flag, you can also use negative glob to `--excludes`
config: # The following configuration will adjust output to the defaults of Apollo-Codegen, and should be compatible with most use-cases.
  preResolveTypes: true # Simplifies the generated types
  namingConvention: keep # Keeps naming as-is
  avoidOptionals: # Avoids optionals on the level of the field
    field: true
  nonOptionalTypename: true # Forces `__typename` on all selection sets
  skipTypeNameForRoot: true # Don't generate __typename for root types
generates: 
  ./src/globalTypes.ts: # Equivalent for `--globalTypesFile` flag
    plugins:
      - typescript # Generates based types based on your schema
 ./src/: # Points to your project root directory.
    preset: near-operation-file # Tells codegen to generate multiple files instead of one
    presetConfig: {
      extension: ".graphql.interface.ts" # Matches the existing Apollo-Codegen file-naming
      baseTypesPath: "./globalTypes.ts" # Points to the base types file
    plugins:
      - typescript-operations # Generates types based on your operations

This should create output that is very similar and compatible with the existing Apollo-Codegen implementation, and should make it simpler for you to migrate.
Also, most of the configuration flags of Apollo-Codegen are supported in codegen, so if you are using custom setup, you should be able to use the base file above.

If your codebase is using intermediate types, you can add typescript-compatibility plugin to get those generated for you.

List of issues / PRs and their state compared to GraphQL-Codegen

Issues

PRs

Configuration mapping

The following is a reference for configuration mapping between Apollo-Codegen and GraphQL-Codegen, you might find it helpful it you are in the process of migrating it:

  • graph / variant / key => You can use apollo-graph loader for that.
  • addTypename => addTypename
  • customScalarsPrefix / passthroughCustomScalars => scalars
  • outputFlat => Not supported, but could be added as a preset.
  • globalTypesFile => simply change the output name in codegen config.
  • excludes => negative glob in documents section
  • endpoint / header / localSchemaFile => schema item, with url loader.
  • includes => documents
  • mergeInFieldsFromFragmentSpreads => flattenGeneratedTypes flag.
  • namespace => wrapper with add plugin
  • tagName => pluckConfig
  • target => list of plugins - this will support only flow / typescript
  • tsFileExtension => will update the output extension, but also we need to make sure to change some configurations related to enums (for example enumAsType: true) if the extension if .d.ts.
  • useFlowExactObjects => flow only, useFlowExactObjects
  • useFlowReadOnlyTypes => flow only, useFlowReadOnlyTypes
  • useReadOnlyTypes => immutableTypes configuration flag

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions