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:
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).
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)
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
preset) if you wish to. possibleTypes object required by Apollo-Client.DocumentNode - codegen can pre-compile GraphQL operations into DocumentNode and eliminate the need for graphql-tag.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.
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.
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.
Issues
* https://github.com/apollographql/apollo-tooling/issues/1414 - graphql-codegen have it by default, and it’s customizable (`namingConvention`) * https://github.com/apollographql/apollo-tooling/issues/1414#issuecomment-627727600 - Maybe we can create a plugin for intermediate types, just for annoying people like that. I think our recent blog post about codegen will help * https://github.com/apollographql/apollo-tooling/issues/979 - We have it built-in in our loaders, you can pass assumeValidSDL and it will skip validation. Maybe it should be better documented. * https://github.com/apollographql/apollo-tooling/issues/1568 - In our codegen it will generate it correctly, and you’ll be able to use `__typename` to identify the type correctly ;) * https://github.com/apollographql/apollo-tooling/issues/622 - `maybeValue` in config * https://github.com/apollographql/apollo-tooling/issues/1388 - Works in codegen, we can load fragment from packages (either code or exports) * https://github.com/apollographql/apollo-tooling/issues/1436 - Works in our codegen, throws error. * https://github.com/apollographql/apollo-tooling/issues/888 - Not supported yet. * https://github.com/apollographql/apollo-tooling/issues/1803 - Codegen will throw an error (valid behaviour) * https://github.com/apollographql/apollo-tooling/issues/1800 - Available in codegen (`useExactValue` config) * https://github.com/apollographql/apollo-tooling/issues/1767 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/988 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1043 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1044 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1735 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1204 - We prefer not to use namespaces in TS. But we do have an example for wrapping all types with an interface (using add plugin). * https://github.com/apollographql/apollo-tooling/issues/791 - In codegen it’s possible to add it manually to the codegen schema, so it will work. * https://github.com/apollographql/apollo-tooling/issues/1576 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1297 - Codegen status update is based on listr, and not verbose when not needed. * https://github.com/apollographql/apollo-tooling/issues/1366 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/604 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1161 - Not needed in codegen. * https://github.com/apollographql/apollo-tooling/issues/1310 - Not needed in codegen. * https://github.com/apollographql/apollo-tooling/issues/1207 - Not needed in codegen. * https://github.com/apollographql/apollo-tooling/issues/1036 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/873 - Available in codegen, because we load everything from scratch every execution. * https://github.com/apollographql/apollo-tooling/issues/1375 - Works in codegen. * https://github.com/apollographql/apollo-tooling/issues/1046 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/932 - Works in codegen. * https://github.com/apollographql/apollo-tooling/issues/833 - Codegen does that by default. * https://github.com/apollographql/apollo-tooling/issues/877 - Available in codegen. * https://github.com/apollographql/apollo-tooling/issues/1223 - You can distinguish types with __typename easily. * https://github.com/apollographql/apollo-tooling/issues/1760 - Codegen doesn’t change the sort, it will be used as-is, using graphql-js library. * https://github.com/apollographql/apollo-tooling/issues/1920 - Codegen doesn’t stop during watch mode, it just waits for changes and re-runs. * https://github.com/apollographql/apollo-tooling/issues/1850 - Codegen works with Yarn2 PnP. * https://github.com/apollographql/apollo-tooling/issues/2016 - Codegen allows you to customize the output and choose between interface or type. * https://github.com/apollographql/apollo-tooling/issues/2030 - Codegen doesn’t produce empty files. * https://github.com/apollographql/apollo-tooling/issues/2044 - Field policies can be represented as a GraphQL schema, and then loaded directly into Codegen just like any other schemas.
PRs
* https://github.com/apollographql/apollo-tooling/pull/1854 - Not supported in codegen yet. * https://github.com/apollographql/apollo-tooling/pull/2043 - It shouldn’t change it in codegen. * https://github.com/apollographql/apollo-tooling/pull/1766 - Configurable with `avoidOptionals` config. * https://github.com/apollographql/apollo-tooling/pull/1750 - Available using `enumsAsTypes` * https://github.com/apollographql/apollo-tooling/pull/1504 - Codegen supports loading schema from local files, url and more.
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 => addTypenamecustomScalarsPrefix / passthroughCustomScalars => scalarsoutputFlat => Not supported, but could be added as a preset.globalTypesFile => simply change the output name in codegen config.excludes => negative glob in documents sectionendpoint / header / localSchemaFile => schema item, with url loader.includes => documentsmergeInFieldsFromFragmentSpreads => flattenGeneratedTypes flag.namespace => wrapper with add plugintagName => pluckConfigtarget => list of plugins - this will support only flow / typescripttsFileExtension => 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, useFlowExactObjectsuseFlowReadOnlyTypes => flow only, useFlowReadOnlyTypesuseReadOnlyTypes => immutableTypes configuration flagThank you for this. I was interested in using hook generation and it looks like this is a good guide for me to migrate.
@dotansimha one thing left out is the apollo option of --passthroughCustomScalars. What I did was add the scalars key to my codegen.yml file:
config:
scalars:
DateTime: string
Float: number
...
Most helpful comment
@dotansimha one thing left out is the apollo option of
--passthroughCustomScalars. What I did was add the scalars key to my codegen.yml file: