According to the docs args are optional by default:
class RechargeSim(graphene.Mutation):
class Arguments:
msisdn = graphene.String(required=True)
network_id = graphene.String(required=True)
product_id = graphene.String()
airtime_amount = graphene.Float()
Here is a query:
result = authed_graphql_client.execute(
'''
mutation($msisdn: String!, $networkId: String!, $productId: String!) {
rechargeSim(msisdn: $msisdn,
networkId: $networkId,
productId: $productId) {
rechargeId
message
}
}
''',
variable_values={
'msisdn': sim.msisdn,
'networkId': network_id,
'productId': product_id
}
)
I get this error:
TypeError: mutate() missing 1 required positional argument: 'airtime_amount'
I have tried the following variations:
class RechargeSim(graphene.Mutation):
class Arguments:
msisdn = graphene.String(required=True)
network_id = graphene.String(required=True)
product_id = graphene.String()
airtime_amount = graphene.Float(required=False)```
class RechargeSim(graphene.Mutation):
class Arguments:
msisdn = graphene.String(required=True)
network_id = graphene.String(required=True)
product_id = graphene.String()
airtime_amount = graphene.Float(default_value=None)```
class RechargeSim(graphene.Mutation):
class Arguments:
msisdn = graphene.String(required=True)
network_id = graphene.String(required=True)
product_id = graphene.String()
airtime_amount = graphene.Float(required=False, default_value=None)```
In the end I have hacked around this by defaulting the value to 0 and then resetting it to None in the resolver if 0.
@lee-flickswitch can you show me your def mutate(...) function? Because I can't reproduce your issue? Also what graphene version are you using?
class RechargeSim(graphene.Mutation):
class Arguments:
msisdn = graphene.String(required=True)
network_id = graphene.ID(required=True)
product_id = graphene.ID(default_value='')
airtime_amount = graphene.Float(default_value=0)
recharge_id = graphene.Int()
message = graphene.String()
@staticmethod
@graphql_secure
def mutate(root, info, msisdn, network_id, product_id, airtime_amount):
organisation = info.context.organisation
if not organisation.allow_recharges_via_api:
error = (
'You do not have permission to perform recharges via the API,'
' please contact support to request access.'
)
raise Exception(error)
if not organisation.recharge_callback_url:
raise Exception('Please configure your Recharge Callback URL under Settings')
# HACK: Optional fields do not seem to be working,
# so we default to 0 in the field definition and then reset it here
# Defaulting to None falls over.
if airtime_amount == 0:
airtime_amount = None
_, network_id = from_global_id(network_id)
if product_id:
_, product_id = from_global_id(product_id)
data = {
'msisdn': msisdn,
'network': network_id,
'product': product_id,
'airtime_amount': airtime_amount
}
form = AdhocRechargeForm(organisation, data)
if not form.is_valid():
raise Exception(form.errors.as_data())
adhoc_recharge_id = form.recharge()
notification = 'Request Queued. Status will be POSTed to your callback URL when ready'
return RechargeSim(recharge_id=adhoc_recharge_id, message=notification)
here are all the versions of the related libs:
graphene 2.1
graphene-django 2.0.0
graphql-core 2.0
graphql-relay 0.4.5
Yep so because airtime_amount is an optional field, when it is not provided in your mutation it won't be passed to your mutate function and that is causing the error. Replace your mutate function def with:
def mutate(root, info, msisdn, network_id, **kwargs):
product_id = kwargs.get('product_id', None)
airtime_amount = kwargs.get('airtime_amount', None)
The reason why it's not passed to your mutate function if it's not defined is so that you can differentiate between it being 'undefined' and it being null.
@jkimbo Doesn't this contradict the documentation at https://github.com/graphql-python/graphene/blob/master/UPGRADE-v2.0.md ? See "Simpler resolvers" before/after.
With graphene 2.x "null" values are not supported. Either a mutation argument is present and has a (non-null) value, then it's part of kwargs or it's absent and not part of kwargs at all. We took the workaround of allowing an empty string for mutation field that represents an ID. We interprete empty strings as null.
Just checking, but what if I define my mutation like this:
def mutate(self, info, required_arg, optional_arg=None):
if optional_arg:
do_something_cool()
Rather than doing kwargs.get("optional_arg", None)? It works on first pass, but not sure if I'm screwing something up internally.
@larsblumberg Seconded. Null values are dropped and there is no way to differentiate between null and undefined.
@jkimbo Has something changed that has caused the functionality of undefined/null to stop working?
Most helpful comment
Yep so because
airtime_amountis an optional field, when it is not provided in your mutation it won't be passed to yourmutatefunction and that is causing the error. Replace yourmutatefunction def with:The reason why it's not passed to your mutate function if it's not defined is so that you can differentiate between it being 'undefined' and it being null.