Django Graphene, Passing JSON or dict data as input for Mutation
Asked Answered
T

2

7

I have the following situation: I have a User, each user has a Inventory. I'm struggling to declare the user's inventory in the Mutation "CreateUser". Here is the following mutation for creating the user:

mutation Create{
  addUser(UserData:{name:"Shibunika",age:21}
}

I'm trying to declare the user's inventory in this mutation, I expected something like

mutation Create{
  addUser(UserData:{name:"Shibunika",age:21,inventory:{'item1':45,'item2':25}
}s

these number are the quantity of each item. How do I define these inputs in graphene? Would you gently show me a schema for this?

Tobin answered 7/7, 2018 at 15:18 Comment(0)
T
12

You can create a custom object type to represent a key value pair, and then have a list of these in your user schema.

class InventoryKeyValueType(graphene.InputObjectType):
    name = graphene.String(required=True)
    int_value = graphene.Int(required=True)

class AddUser(graphene.Mutation):
    user = graphene.Field(lambda: UserType)
    ok = graphene.Boolean()

    class Arguments:
        # User Fields
        name = graphene.String()
        ....

        inventory = graphene.List(InventoryKeyValueType)

The syntax is a bit clunky but workable:

mutation { addUser(name:"Shibunika", age:21, inventory:[ {name: "item1", intValue: 45}, {name: "item2", intValue:25}]){ok}

Other Input Types

This approach could easily be extended for other input types beyond integers, for example replacing

    int_value = graphene.Int(...

with

    str_value = graphene.String(...
Their answered 10/7, 2018 at 15:25 Comment(2)
excellent answer, thanks – now for people who are as dense as me, please note how the type that inventory is expecting is derived from InputObjectType and NOT ObjectType....Jacynth
inventory requires a List of InventoryKeyValueType objects, which inherit from InputObjectTypeTheir
J
3

Graphene provides a GenericScalar type. You can use it to input/output generic types like int, str, dict, list, etc.

from graphene import InputObjectType, Mutation, String, Int
from graphene.types.generic import GenericScalar

class UserInput(InputObjectType):
    name = String()
    age = Int()
    inventory = GenericScalar()

class addUser(Mutation):
    class Arguments:
        user_data = UserInput()

    def mutate(root, info, user_data):
        # do something with user_data

Your input would look like

mutation Create {
  addUser (
    userData: {
      name: "Shibunika"
      age: 21
      inventory: {
        item1: 45,
        item2: 25
      }
    }
  )
}

Note that inventory can accept any generic input, so make sure to validate it.

Also, when using a GenericScalar field for output (query), you won't be able to query its subfields e.g. item1, item2. But you can write a resolver for that field to make sure only specific subfields are returned.

Here is the link to the corresponding GitHub issue.

In your case, inventory field has a well-defined structure, so Mark Chackerian's solution fits better.

Jessee answered 2/4, 2021 at 13:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.