Skip to content

Commit 99aac7b

Browse files
Add --graphql-no-typename option to exclude typename field (#2899)
* Add --graphql-no-typename option to exclude typename field * docs: update CLI reference documentation and prompt data 🤖 Generated by GitHub Actions --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 87445c8 commit 99aac7b

19 files changed

Lines changed: 308 additions & 1 deletion

File tree

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# 📋 GraphQL-only Options
2+
3+
## 📋 Options
4+
5+
| Option | Description |
6+
|--------|-------------|
7+
| [`--graphql-no-typename`](#graphql-no-typename) | Exclude __typename field from generated GraphQL models. |
8+
9+
---
10+
11+
## `--graphql-no-typename` {#graphql-no-typename}
12+
13+
Exclude __typename field from generated GraphQL models.
14+
15+
The `--graphql-no-typename` flag prevents the generator from adding the
16+
`typename__` field (aliased to `__typename`) to generated models. This is
17+
useful when using generated models for GraphQL mutations, as servers typically
18+
don't expect this field in input data.
19+
20+
!!! tip "Usage"
21+
22+
```bash
23+
datamodel-codegen --input schema.json --graphql-no-typename # (1)!
24+
```
25+
26+
1. :material-arrow-left: `--graphql-no-typename` - the option documented here
27+
28+
??? example "Examples"
29+
30+
**Input Schema:**
31+
32+
```graphql
33+
type Book {
34+
id: ID!
35+
title: String
36+
}
37+
38+
interface Node {
39+
id: ID!
40+
}
41+
42+
input BookInput {
43+
title: String!
44+
}
45+
```
46+
47+
**Output:**
48+
49+
```python
50+
# generated by datamodel-codegen:
51+
# filename: no-typename.graphql
52+
# timestamp: 2019-07-26T00:00:00+00:00
53+
54+
from __future__ import annotations
55+
56+
from typing import TypeAlias
57+
58+
from pydantic import BaseModel
59+
60+
Boolean: TypeAlias = bool
61+
"""
62+
The `Boolean` scalar type represents `true` or `false`.
63+
"""
64+
65+
66+
ID: TypeAlias = str
67+
"""
68+
The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
69+
"""
70+
71+
72+
String: TypeAlias = str
73+
"""
74+
The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
75+
"""
76+
77+
78+
class Node(BaseModel):
79+
id: ID
80+
81+
82+
class Book(BaseModel):
83+
id: ID
84+
title: String | None = None
85+
86+
87+
class BookInput(BaseModel):
88+
title: String
89+
```
90+
91+
---
92+

docs/cli-reference/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This documentation is auto-generated from test cases.
1414
| 🏗️ [Model Customization](model-customization.md) | 39 | Model generation behavior |
1515
| 🎨 [Template Customization](template-customization.md) | 18 | Output formatting and custom rendering |
1616
| 📘 [OpenAPI-only Options](openapi-only-options.md) | 7 | OpenAPI-specific features |
17+
| 📋 [GraphQL-only Options](graphql-only-options.md) | 1 | |
1718
| ⚙️ [General Options](general-options.md) | 15 | Utilities and meta options |
1819
| 📝 [Utility Options](utility-options.md) | 6 | Help, version, debug options |
1920

@@ -94,6 +95,7 @@ This documentation is auto-generated from test cases.
9495
- [`--generate-cli-command`](general-options.md#generate-cli-command)
9596
- [`--generate-prompt`](utility-options.md#generate-prompt)
9697
- [`--generate-pyproject-config`](general-options.md#generate-pyproject-config)
98+
- [`--graphql-no-typename`](graphql-only-options.md#graphql-no-typename)
9799

98100
### H {#h}
99101

docs/cli-reference/quick-reference.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ datamodel-codegen [OPTIONS]
162162
| [`--use-status-code-in-response-name`](openapi-only-options.md#use-status-code-in-response-name) | Include HTTP status code in response model names. |
163163
| [`--validation`](openapi-only-options.md#validation) | Enable validation constraints (deprecated, use --field-constraints). |
164164

165+
### 📋 GraphQL-only Options
166+
167+
| Option | Description |
168+
|--------|-------------|
169+
| [`--graphql-no-typename`](graphql-only-options.md#graphql-no-typename) | Exclude __typename field from generated GraphQL models. |
170+
165171
### ⚙️ General Options
166172

167173
| Option | Description |
@@ -251,6 +257,7 @@ All options sorted alphabetically:
251257
- [`--generate-cli-command`](general-options.md#generate-cli-command) - Generate CLI command from pyproject.toml configuration.
252258
- [`--generate-prompt`](utility-options.md#generate-prompt) - Generate a prompt for consulting LLMs about CLI options
253259
- [`--generate-pyproject-config`](general-options.md#generate-pyproject-config) - Generate pyproject.toml configuration from CLI arguments.
260+
- [`--graphql-no-typename`](graphql-only-options.md#graphql-no-typename) - Exclude __typename field from generated GraphQL models.
254261
- [`--help`](utility-options.md#help) - Show help message and exit
255262
- [`--http-headers`](general-options.md#http-headers) - Fetch schema from URL with custom HTTP headers.
256263
- [`--http-ignore-tls`](general-options.md#http-ignore-tls) - Disable TLS certificate verification for HTTPS requests.

docs/graphql.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,39 @@ class A(BaseModel):
207207

208208
---
209209

210+
## 🚫 Excluding __typename Field
211+
212+
When using generated models for GraphQL mutations, the `__typename` field may cause issues
213+
as GraphQL servers typically don't expect this field in input data.
214+
215+
Use the `--graphql-no-typename` option to exclude this field:
216+
217+
```bash
218+
datamodel-codegen --input schema.graphql --input-file-type graphql --output model.py --graphql-no-typename
219+
```
220+
221+
**Before (default):**
222+
```python
223+
class Book(BaseModel):
224+
id: ID
225+
title: String | None = None
226+
typename__: Literal['Book'] | None = Field('Book', alias='__typename')
227+
```
228+
229+
**After (with --graphql-no-typename):**
230+
```python
231+
class Book(BaseModel):
232+
id: ID
233+
title: String | None = None
234+
```
235+
236+
!!! warning "Union Type Discrimination"
237+
If your schema uses GraphQL union types and you rely on `__typename` for type
238+
discrimination during deserialization, excluding this field may break that functionality.
239+
Consider using this option only for input types or schemas without unions.
240+
241+
---
242+
210243
## 📖 See Also
211244

212245
- 🖥️ [CLI Reference](cli-reference/index.md) - Complete CLI options reference

src/datamodel_code_generator/__main__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ def validate_class_name_affix_scope(cls, v: str | ClassNameAffixScope | None) ->
551551
openapi_scopes: Optional[list[OpenAPIScope]] = [OpenAPIScope.Schemas] # noqa: UP045
552552
include_path_parameters: bool = False
553553
openapi_include_paths: Optional[list[str]] = None # noqa: UP045
554+
graphql_no_typename: bool = False
554555
wrap_string_literal: Optional[bool] = None # noqa: UP045
555556
use_title_as_name: bool = False
556557
use_operation_id_as_name: bool = False
@@ -929,6 +930,7 @@ def run_generate_from_config( # noqa: PLR0913, PLR0917
929930
openapi_scopes=config.openapi_scopes,
930931
include_path_parameters=config.include_path_parameters,
931932
openapi_include_paths=config.openapi_include_paths,
933+
graphql_no_typename=config.graphql_no_typename,
932934
wrap_string_literal=config.wrap_string_literal,
933935
use_title_as_name=config.use_title_as_name,
934936
use_operation_id_as_name=config.use_operation_id_as_name,
@@ -1000,6 +1002,9 @@ def run_generate_from_config( # noqa: PLR0913, PLR0917
10001002

10011003
def main(args: Sequence[str] | None = None) -> Exit: # noqa: PLR0911, PLR0912, PLR0914, PLR0915
10021004
"""Execute datamodel code generation from command-line arguments."""
1005+
vars(namespace).clear()
1006+
namespace.no_color = False
1007+
10031008
if "_ARGCOMPLETE" in os.environ: # pragma: no cover
10041009
import argcomplete # noqa: PLC0415
10051010

src/datamodel_code_generator/_types/generate_config_dict.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class GenerateConfigDict(TypedDict):
104104
include_path_parameters: NotRequired[bool]
105105
openapi_include_paths: NotRequired[list[str] | None]
106106
graphql_scopes: NotRequired[list[GraphQLScope] | None]
107+
graphql_no_typename: NotRequired[bool]
107108
wrap_string_literal: NotRequired[bool | None]
108109
use_title_as_name: NotRequired[bool]
109110
use_operation_id_as_name: NotRequired[bool]

src/datamodel_code_generator/_types/parser_config_dicts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ class ParserConfigDict(TypedDict):
152152
class GraphQLParserConfigDict(ParserConfigDict):
153153
data_model_scalar_type: NotRequired[type[DataModel]]
154154
data_model_union_type: NotRequired[type[DataModel]]
155+
graphql_no_typename: NotRequired[bool]
155156

156157

157158
class JSONSchemaParserConfigDict(ParserConfigDict):

src/datamodel_code_generator/arguments.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ def start_section(self, heading: str | None) -> None:
103103
extra_fields_model_options = model_options.add_mutually_exclusive_group()
104104
template_options = arg_parser.add_argument_group("Template customization")
105105
openapi_options = arg_parser.add_argument_group("OpenAPI-only options")
106+
graphql_options = arg_parser.add_argument_group("GraphQL-only options")
106107
general_options = arg_parser.add_argument_group("General options")
107108

108109
# ======================================================================================
@@ -958,6 +959,17 @@ def start_section(self, heading: str | None) -> None:
958959
default=None,
959960
)
960961

962+
# ======================================================================================
963+
# Options specific to GraphQL input schemas
964+
# ======================================================================================
965+
graphql_options.add_argument(
966+
"--graphql-no-typename",
967+
help="Exclude __typename field from generated GraphQL models. "
968+
"Useful when using generated models for GraphQL mutations.",
969+
action="store_true",
970+
default=None,
971+
)
972+
961973
# ======================================================================================
962974
# General options
963975
# ======================================================================================

src/datamodel_code_generator/cli_options.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class OptionCategory(str, Enum):
2424
MODEL = "Model Customization"
2525
TEMPLATE = "Template Customization"
2626
OPENAPI = "OpenAPI-only Options"
27+
GRAPHQL = "GraphQL-only Options"
2728
GENERAL = "General Options"
2829

2930

@@ -244,6 +245,10 @@ class CLIOptionMeta:
244245
deprecated_message="Use --field-constraints instead",
245246
),
246247
# ==========================================================================
248+
# GraphQL-only Options
249+
# ==========================================================================
250+
"--graphql-no-typename": CLIOptionMeta(name="--graphql-no-typename", category=OptionCategory.GRAPHQL),
251+
# ==========================================================================
247252
# General Options
248253
# ==========================================================================
249254
"--check": CLIOptionMeta(name="--check", category=OptionCategory.GENERAL),

src/datamodel_code_generator/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ class Config:
141141
include_path_parameters: bool = False
142142
openapi_include_paths: list[str] | None = None
143143
graphql_scopes: list[GraphQLScope] | None = None
144+
graphql_no_typename: bool = False
144145
wrap_string_literal: bool | None = None
145146
use_title_as_name: bool = False
146147
use_operation_id_as_name: bool = False
@@ -336,6 +337,7 @@ class GraphQLParserConfig(ParserConfig):
336337

337338
data_model_scalar_type: type[DataModel] = DataTypeScalar
338339
data_model_union_type: type[DataModel] = DataTypeUnion
340+
graphql_no_typename: bool = False
339341

340342

341343
class JSONSchemaParserConfig(ParserConfig):

0 commit comments

Comments
 (0)