Generate Input Arguments from SQLAlchemy Class?
Hello, Do you know if it's possible to generate input arguments dynamically from the SQLAlchemy class that will be transformed by the mutation? Example:
My input arguments for a CreatePerson mutation look like this:
class CreatePersonInput(graphene.InputObjectType):
"""Arguments to create a person."""
name = graphene.String(required=True, description="Name of the person to be created.")
height = graphene.String(default_value="unknown", description="Height of the person to be created.")
mass = graphene.String(default_value="unknown", description="Mass of the person to be created.")
hair_color = graphene.String(default_value="unknown", description="Hair color of the person to be created.")
skin_color = graphene.String(default_value="unknown", description="Skin color of the person to be created.")
eye_color = graphene.String(default_value="unknown", description="Eye color of the person to be created.")
birth_year = graphene.String(default_value="unknown", description="Birth year of the person to be created.")
gender = graphene.String(default_value="unknown", description="Gender of the person to be created.")
planet_id = graphene.ID(default_value="unknown", description="Global Id of the planet from which the person to be created comes from.")
url = graphene.String(default_value="unknown", description="URL of the person in the Star Wars API.")
class CreatePerson(graphene.Mutation):
"""Mutation to create a person."""
person = graphene.Field(lambda: People, description="Person created by this mutation.")
class Arguments:
input = CreatePersonInput(required=True)
...
In the meantime, the input arguments for my UpdatePerson mutation look like this:
class UpdatePersonInput(graphene.InputObjectType):
"""Arguments to update a person."""
id = graphene.ID(required=True)
name = graphene.String()
height = graphene.String()
mass = graphene.String()
hair_color = graphene.String()
skin_color = graphene.String()
eye_color = graphene.String()
birth_year = graphene.String()
gender = graphene.String()
planet_id = graphene.ID()
url = graphene.String()
class UpdatePerson(graphene.Mutation):
"""Update a person."""
person = graphene.Field(lambda: People, description="Person updated by this mutation.")
class Arguments:
input = UpdatePersonInput(required=True)
...
Finally, my SQLAlchemy class look like this:
class ModelPeople(Base):
"""People model."""
__tablename__ = 'people'
id = Column('id', Integer, primary_key=True)
name = Column('name', String)
height = Column('height', String)
mass = Column('mass', String)
hair_color = Column('hair_color', String)
skin_color = Column('skin_color', String)
eye_color = Column('eye_color', String)
birth_year = Column('birth_year', String)
gender = Column('gender', String)
planet_id = Column('planet_id', Integer, ForeignKey('planet.id'))
created = Column('created', String)
edited = Column('edited', String)
url = Column('url', String)
...
This is all pretty redundant and it would be ideal if we could just reuse the SQLAlchemy class attributes in the InputObjectType
I was able to factorize my code a little bit by creating a new class where I define attributes description only once. Then I supply this new class as a parent class of the following classes:
-
class People(SQLAlchemyObjectType, PeopleAttribute): used for GraphQL queries -
class CreatePersonInput(graphene.InputObjectType, PeopleAttribute): used to define inputs for GraphQL create mutation -
class UpdatePersonInput(graphene.InputObjectType, PeopleAttribute): used to define inputs for GraphQL create mutation
Here is the code:
# Create a generic class to mutualize description of people attributes for both queries and mutations
class PeopleAttribute:
name = graphene.String(required=True, description="Name of the person.")
height = graphene.String(default_value="unknown", description="Height of the person.")
mass = graphene.String(default_value="unknown", description="Mass of the person.")
hair_color = graphene.String(default_value="unknown", description="Hair color of the person.")
skin_color = graphene.String(default_value="unknown", description="Skin color of the person.")
eye_color = graphene.String(default_value="unknown", description="Eye color of the person.")
birth_year = graphene.String(default_value="unknown", description="Birth year of the person.")
gender = graphene.String(default_value="unknown", description="Gender of the person.")
planet_id = graphene.ID(default_value="unknown", description="Global Id of the planet from which the person comes from.")
url = graphene.String(default_value="unknown", description="URL of the person in the Star Wars API.")
class People(SQLAlchemyObjectType, PeopleAttribute):
"""People node."""
class Meta:
model = ModelPeople
interfaces = (graphene.relay.Node,)
class CreatePersonInput(graphene.InputObjectType, PeopleAttribute):
"""Arguments to create a person."""
pass
class UpdatePersonInput(graphene.InputObjectType, PeopleAttribute):
"""Arguments to update a person."""
id = graphene.ID(required=True, description="Global Id of the person.")
Does anyone has a better way of doing this? I have also posted the question here : https://stackoverflow.com/questions/48806710/generate-graphene-mutation-inputs-from-sqlalchemy-class-attributes
See this also: https://github.com/graphql-python/graphene-sqlalchemy/issues/29