Skip to content

Graphql - Generate pydantic schema for grahpql query objects #2526

@Cnoor0171

Description

@Cnoor0171

Is your feature request related to a problem? Please describe.
This library lets you generate pydantic types from graohql schemas. But responses from a server can't be validated against that pydantic class because the request can contain only a subset of the fields from the gql schema so even required fields may be None. You can get around this issue using the --force-optional flag, but that makes every field optional, even the ones that were included in the request.

It would be awesome if users were also able to specify the query object they are using so the generated types can have the appropriate fields be mandatory.

Describe the solution you'd like
In the input file, along with the graphql schema definition elements, allow query definitions. Each query should generate its own pydantic class with only the queried fields present. The field should be optional if the schema defines it as optional. It should be missing if the query doesn't include it.

Eaxample:

# schema.gql
type Query {
    getProducts: GetProductsResponse!
    getTags: GetTagsResponse!
}

type GetProductsResponse {
    id: Int!
    name: String!
}

type GetTagsResponse {
    id: Int!
    name: String
}


query getAllProducts {
    getProducts {
        id
        name
    }
}

query getAllTags {
    getTags {
        name
    }
}

Could generate (run python -m datamodel_code_generator --input-file-type=graphql --input=schema.gql --output-model-type=pydantic_v2.BaseModel --output schema.py):

# generated by datamodel-codegen:
#   filename:  schema.gql
#   timestamp: 2025-10-28T16:27:05+00:00

from __future__ import annotations

from typing import Literal, Optional, TypeAlias

from pydantic import BaseModel, Field

Boolean: TypeAlias = bool
"""
The `Boolean` scalar type represents `true` or `false`.
"""


Int: TypeAlias = int
"""
The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
"""


String: TypeAlias = str
"""
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.
"""


class GetProductsResponse(BaseModel):
    id: Int
    name: String
    typename__: Optional[Literal['GetProductsResponse']] = Field(
        'GetProductsResponse', alias='__typename'
    )


class GetTagsResponse(BaseModel):
    id: Int
    name: Optional[String] = None
    typename__: Optional[Literal['GetTagsResponse']] = Field(
        'GetTagsResponse', alias='__typename'
    )


# These are the proposed types to be generated from the queries
class QueryGetAllProducts(BaseModel):
    getProducts: QueryGetAllProductsGetProducts

class QueryGetAllProductsGetProducts(BaseModel):
    id: Int
    typename__: Optional[Literal['GetProductsResponse']] = Field(
        'GetProductsResponse', alias='__typename'
    )


class QueryGetAllTags(BaseModel):
    getTags: QueryGetAllTagsGetTags

class QueryGetAllTagsGetTags(BaseModel):
    name: Optional[String] = None
    typename__: Optional[Literal['GetTagsResponse']] = Field(
        'GetTagsResponse', alias='__typename'
    )

Describe alternatives you've considered

  • Have this be in a completely separate library. Doesn't seem necessary since this library is already doing most of the heavy lifting.
  • Have a separate --input-file-type for this. Ideally I would like to have each query as a separate .gql file, but generating the models requires both the schema definition and the query, so I figured combining them would make sense. If there is a way to provide the schema definition file though (maybe a separate flag), I think this would be even better.

Additional context
Add any other context or screenshots about the feature request here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions