2

As per the GraphQL spec https://graphql.github.io/graphql-spec/draft/#sec-Input-Objects

the input object literal or unordered map must not contain any entries with names not defined by a field of this input object type, otherwise an error must be thrown.

Let's say I have a project which has a user called buyer, the schema for which is as follows

type Buyer {
     id: ID!
     name: String!
     address: String!
     email: String!
}

Now I can write a graphene schema for it

class BuyerType(DjangoObjectType):
    class Meta:
        model = Buyer

and make a mutation for this

class BuyerInput(graphene.InputObjectType):
    name = graphene.String(required=False, default_value='')
    address = graphene.String(required=False, default_value='')
    email = graphene.String(required=False, default_value='')


class BuyerMutation(graphene.Mutation):
    """
    API to create applicant
    """
    class Arguments:
        buyer_data = BuyerInput(required=True)


    buyer = graphene.Field(BuyerType)
    ok = graphene.Boolean()

    def mutate(self, info, buyer_data=None):
           buyer = Buyer(name=buyer.name, address=buyer.address, email=buyer.email)
           buyer.save()
           return BuyerMutation(buyer=buyer, ok=True)

and write the resolvers functions and query and mutation class. Pretty basic stuff so far.

And now to create a new buyer, I just call the mutation

mutation {
   createBuyer(
           name: "New Buyer"
           address: "Earth"
           email: "abc@example.com"
  ) {
      ok
  }
}

But if I pass an additional field called phone

mutation {
   createBuyer(
           name: "New Buyer"
           address: "Earth"
           email: "abc@example.com"
           phone: 8541345474
  ) {
      ok
  }
}

an Unknown field 'phone' error comes up, which is understood.

But I want to make process for frontend devs easier. Rather than mentioning each field in the argument of mutation, they can just pass a dict which contains these three fields and also other arguments that might originate from a form submission, and then read the dict in the backend and only extract the fields that I need, much like it is done with REST APIs.

If this is possible, then how can I implement this?

Prabhu Pant
  • 71
  • 2
  • 2
  • GraphQL is intentionally strongly typed. Workarounds may exist to implement functionality that **breaks** the spec, but you should generally avoid doing so. Breaking the spec is likely to break other tools or libraries you're using, like GraphQL Playground or whatever client library you're using on the front end (Apollo, Relay, etc.). It's also going to cause unnecessary confusion for any member of your team that is already familiar with GraphQL. Wanting to make form submission easier probably doesn't warrant such a drastic approach. – Daniel Rearden Nov 12 '19 at 12:32

1 Answers1

0

We could get the class attributes of BuyerInput using the inspect module, and then assemble the arguments dictionary so that it ignores the keys which are not such an attribute. Say, we have the dict containing the parameters of createBuyer stored in the variable kwargs, this could look like the following:

import inspect


members = inspect.getmembers(BuyerInput, lambda a: not(inspect.isroutine(a)))
attributes = [
    tup[0] 
    for tup in members 
    if not tup[0].startswith("_")
]

kwargs = {
    key: value
    for key, value in kwargs.items()
    if key in attributes
}
Jonathan Scholbach
  • 4,925
  • 3
  • 23
  • 44