menu

Questions & Answers

How can I add a list of fields dynamically to GraphQL ObjectType

I have the following code:

from starlette_graphene3 import GraphQLApp
import graphene

app = = APIRouter(
    dependencies=[Depends(auth_middleware)],
)

DYNAMIC_TYPES = {
    "length": graphene.Int(),
    "authors": graphene.List(of_type=str),
    "deprecated": graphene.String()
}

class MetaDataObject(graphene.ObjectType):
    resource_type = graphene.String()
    resource_name = graphene.String()

# I need to be able to do this somehow - specify a list of fieds and types dynamically.
for attr, g_type in DYNAMIC_TYPES.items():
    setattr(MetaDataObject, attr, g_type)


class Query(graphene.ObjectType):
    get_metadata = graphene.Field(MetaDataObject, resource_type=graphene.String(), resource_name=graphene.String())

    def resolve_get_metadata(self, info, resource_type, resource_name):

        response = table.get_item(
            Key={
                'resource_type': resource_type,
                'resource_name': resource_name
            }
        )

        if 'Item' not in response:
            return None

        return response['Item']


schema = graphene.Schema(query=Query, auto_camelcase=False)
app.add_route("/graphql", GraphQLApp(schema=schema))

As indicated above, I need to be able to specify a list of fieds and types dynamically and attach it to the Metadata Object. The issue is that the graphe.ObjectType is not a regular Python class, it has a special metaclass that takes care of some under-the-hood work, but I'm not sure how I can work with the Metaclass.

Answers(1) :

You can create a graphene.Dynamic field in your MetaDataObject class, which can accept a list of fields and types as an argument.

You can use graphene.Field to define the fields, and graphene.List or graphene.NonNull to define the types of the fields.

Like;

class MetaDataObject(graphene.ObjectType):
    resource_type = graphene.String()
    resource_name = graphene.String()
    dynamic_fields = graphene.List(graphene.Field(graphene.String))

You can then pass the list of fields and types to the MetaDataObject class when you create an instance of it.

Like;

metadata_object = MetaDataObject(dynamic_fields=[graphene.Field(graphene.String, name='field_name')])
Comments:
2023-01-24 00:30:05
This does not work: ``` for field in named_type.fields.values(): File "/usr/local/lib/python3.10/functools.py", line 981, in get val = self.func(instance) File "/home/appuser/venv/lib/python3.10/site-packages/graphql/typ‌​e/definition.py", line 811, in fields raise cls(f"{self.name} fields cannot be resolved. {error}") from error TypeError: MetaDataObject fields cannot be resolved. Expected Graphene type, but received: <class 'graphene.types.field.Field'>. ```
2023-01-24 00:30:05
I have edited the answer and tried out it worked for me, let me know if its works for you @JayjayJay