# GraphQL Codegen for TypeScript in Angular
## Existing Solutions
- [GraphQL Code Generator](https://github.com/dotansimha/graphql-code-generator) ([Official Site](https://graphql-code-generator.com/))
- [apollo-tooling](https://github.com/apollographql/apollo-tooling)
We are currently using the **GraphQL Code Generator**.
## What we like
- Locality of the generated files. They are alongside the other component files.
- They generate an Angular Service which can just be injected into the component.
- It works on `some.component.graphql` files instead of using [graphql-tag](https://www.npmjs.com/package/graphql-tag)
## What we don't like
- Global exported types (except Enums and Input Types) which can be accidently imported and used in the App.
- Making it as unfriendly as possible for TypeScript errors (usage of `Pick`, `Maybe`, `Scalars` etc.).
- No type alias for sub fields. Everyting is "inlined" starting from the root type. Making it nearly impossible to alias it and re-use the GraphQL structure oof sub fields inside the App.
## Implementation Options
~~**a) Extend, or fork Apollo Codegen**~~ (we are replacing [apollo-tooling](https://github.com/apollographql/apollo-tooling) with [ngx-urql](https://github.com/alexandercarls/ngx-urql) in the future)
**b) Extend `GraphQL Code Generator`**
For the plugin system we have likely have two options:
1. Replace [TypeScript Plugin](https://github.com/alexandercarls/ngx-urql/blob/master/projects/example/codegen.yaml#L6) and/or [typescript-operations Plugin](https://github.com/alexandercarls/ngx-urql/blob/master/projects/example/codegen.yaml#L14).
2. Add a new plugin which transforms the previous ones.
~~**c) Write our own stuff!**~~ (Option **b)** works for us as it provides a working infrastructure such as CLI and a configuarable plugin architecture)
## Target Concept
Based on the current usage of **GraphQL Code Generator**.
with the following `codegen.yml` configuration
```yml
schema: "http://localhost:5000"
documents: "src/**/*.graphql"
hooks:
afterAllFileWrite:
- prettier --write
generates:
src/types.generated.ts:
- add: "/* tslint:disable */"
- "typescript"
src/:
preset: near-operation-file
presetConfig:
extension: .generated.ts
baseTypesPath: types.generated.ts
plugins:
- add: "/* tslint:disable */"
- "typescript-operations"
- "typescript-apollo-angular"
src/__generated__/fragmentTypes.json:
plugins:
- fragment-matcher
```
**Reduce globally accessible types from `types.generated.ts`.**
Apollo only creates Enum and Input Types ([Example](https://gitlab.intern.atmina.systems/wobcom/abis-prototype/-/blob/981265ce61a12a463e45cb95b69106d0ca11a614/abis.web/__generated__/globalTypes.ts)) while GQL-Codegen creates every GraphQL Type, which has no usage in the application ([Example](https://gitlab.intern.atmina.systems/dguv/kulturcheck-app/-/blob/8dac64281fcaecd818049557b1289adccacea365/frontend/src/types.generated.ts#L48)) and can be wrongly imported.
==> **Solution**: Only generate Enums globally.
**Create plain TypeScript interfaces**.
GQL-Codegen heavily uses abstraction like `Scalars`, `Maybe`, `Pick` etc. which makes the generated interface as well as compile time errors less readable ([Example](https://gitlab.intern.atmina.systems/dguv/kulturcheck-app/-/blob/develop/frontend/src/app/auswertung/services/auswertung.generated.ts#L16)).
==> **Solution**: Generate the TypeScript Code as plainly as possible and minimize abstractions. There is no reason to be as much DRY as GQL-Codegen, hence why we are generating it instead of writing.
**Create an alias for nested types instead of embedding it.**
GQL-Codegen only embeds the interface which makes it really hard or impossible to
a) Re-Use a nested type, especially with a union type ([Example](https://gitlab.intern.atmina.systems/dguv/kulturcheck-app/-/blob/8dac64281fcaecd818049557b1289adccacea365/frontend/src/app/auswertung/services/auswertung.generated.ts#L34)).
b) TypeScript compile time errors are less, if at all, readable.
We are currently creating and missusing lots of GraphQL Fragments to have a generated type alias ([Example](https://gitlab.intern.atmina.systems/dguv/kulturcheck-app/-/blob/8dac64281fcaecd818049557b1289adccacea365/frontend/src/app/shared/services/check.service.graphql#L13)). However, Fragments do not allow passing in variables.
Apollo create a TypeScript Interface for each complex type which name starts with the query/mutation name and followed with the property path ([Example](https://gitlab.intern.atmina.systems/wobcom/abis-prototype/-/blob/981265ce61a12a463e45cb95b69106d0ca11a614/abis.web/src/app/partners/partner/tabs/partner-tk-leitung/__generated__/PartnerTkLeitungenByPartnerId.ts#L23)).
If the name is too long, the developer can type still type alias it.
We can leverage a self-written Directive which our Codegen-Plugin incorporates for the generated interface name.
For example
```graphql=
query GetStrukturAuswertung {
strukturCheck {
id
frageHandlungsfelder @export("Handlungsfeld") {
id
checkTyp
ordinal
titel
frageBloecke @export("FrageBlock") {
id
ordinal
titel
menuTitel
# omitted
}
}
}
}
```
No intermediate interface will be exported for consumption. Only the query itself and fields which are annotated wih `@export` will be publicly accessible from the generated file.
Make sure that the snippets from the `*.graphl`-Files are still copyable to Insomnia etc on its own. It is likely that they throw an error due to an unknown directive. Comments would be prefered here `# export FrageBlock`. However, as of today they are not part of the AST.
==> **Solution** Use the solution from Apollo. Allow for type aliasing with a custom GraphQL Directive
**Create local Angular Services next to the `*.graphql` file.**
==> **Solution** Already implemented.