dotansimha / dotansimha/graphql-code-generator

Ability to override operation field types/nullability via directives

Open
#7,356 3 comments 10 reactions 0 assignees View on GitHub
core kind/enhancement
Dominant language
TypeScript
Stars
11.3k
Forks
1.4k
Avg merge
1d 1h
Merged PRs (30d)
23

Description

## Is your feature request related to a problem? Please describe.

Custom directives can be used to override type definitions for input fields and arguments in the schema, but not for *operation* field types. This would be a useful feature to complement corresponding client or server-side transformations. If you have a large federated graph owned by many teams, data type and nullability conventions can be inconsistent, and changing parts of the schema can be prohibitive. This is where operation-level directives can shine :)

Some examples of how this feature could be used:
* We have a directive called `nonNull` on `FIELD`, which makes our gateway treat a nullable field as if it is a non-nullable field. We would like the generated type definitions to match.
* Suppose you had a `@asString` directive your server supported, e.g. you might use that cast ids from numbers to strings in a query
* A list might allow null entries in the schema but not in practice; it would be nice to avoid having to filter out `null`/`undefined` just to appease TS.
* etc.

## Describe the solution you'd like
Ideally a new configuration setting along these lines:

```ts
type DirectiveFieldMappings = {
/** Name of the FIELD directive */
[name: string]: {
/**
* Override field type, via:
* - type name (e.g. `boolean`)
* - parseMapper string (e.g. `./module#type`)
* - directive argument reference (e.g. `$type` would resolve to the value of the directive's
* `type` arg, which could be a type name or parseMapper string)
*/
type?: string;

/**
* Override field nullability, via:
* - boolean
* - directive argument expression (e.g. `$field` would resolve to the value of the directive's
* `field` arg, which would be a boolean. `!$field` would negate the value)
*/
nullable?: boolean | string;

/**
* Override list entry nullability, via:
* - boolean
* - directive argument expression (e.g. `$entries` would resolve to the value of the directive's
* `entries` arg, which would be a boolean. `!$entries` would negate the value)
*/
nullableEntries?: boolean | string;
};
};
```

## An Example

### Configuration
```yaml
directiveFieldMappings:
nonNull:
nullable: false
nullableEntries: "!$entries"
asString:
type: string
```

### Schema
```graphqls
directive @asString on FIELD
directive @nonNull(entries: Boolean) on FIELD

type User {
id: Int!
username: String
favoriteColors: [String]
}

type Query {
me: User
}

schema {
query: Query
}
```

### Document
```graphql
query {
me {
id @asString
username @nonNull
favoriteColors @nonNull(entries: true)
}
}
```

### Generated type
```ts
export type Unnamed_1_Query = {
__typename?: 'Query',
me: {
__typename?: 'User',
id: string,
username: string,
favoriteColors: Array,
} | null | undefined
}
```

## Describe alternatives you've considered

1. **Write a targeted plugin that adds this functionality**. This was going to be my initial approach, and I'd still be happy to go this route if we can some smaller changes made to graphql-code-generator, e.g. pass along the field's directive nodes to both `formatNamedField` and `wrapTypeWithModifiers`, and make it a little easier to extend/override TypeScriptDocumentsVisitor.
2. **Maintain a full `typescript-operations` fork with this functionality**. Not ideal :)
3. **Maintain bespoke type definitions to match server-side transformations**. Also not ideal :)

## Additional context

* I have the proposal above [implemented and basically ready for a PR](https://github.com/jenseng/graphql-code-generator/commit/60133f2f3a0d80d39e992693fac07dcfc1f441bc) in my own fork 😆
* Previous discussion on this topic: https://github.com/dotansimha/graphql-code-generator/discussions/5676
* Further reading on [client-controlled nullability](https://github.com/graphql/graphql-wg/blob/main/rfcs/ClientControlledNullability.md#a-nonnull-custom-directive)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.