strawberry
strawberry copied to clipboard
Input type is not JSON serializable
Hi @patrick91 -
I'm at a loss for what is going on here.
I've defined an object input type SubscriptionForm
which I am using in a mutation resolver as follows:
@strawberry.input
class PaymentProfileAttributes:
first_name: str
last_name: str
full_number: str
cvv: str
expiration_month: str
expiration_year: str
billing_zip: str
@strawberry.input
class CustomerAttributes:
first_name: str
last_name: str
email: str
phone: Optional[str]
organization: str
reference: str
@strawberry.input
class SubscriptionForm:
agree_to_terms: bool
payment_profile_attributes: PaymentProfileAttributes
customer_attributes: CustomerAttributes
product_handle: str
reference: str
@strawberry.type
class Mutation:
@strawberry.mutation
async def subscribe(self, info: Info, form: SubscriptionForm) -> APIResponse:
...
However the graphql server is erroring with:
{"data":null,"errors":[{"message":"Object of type SubscriptionForm is not JSON serializable","locations":[{"line":2,"column":3}],"path":["subscribe"]}]}
The object being sent to the server looks as follows:
{
"subscription": {
"agreeToTerms": false,
"paymentProfileAttributes": {
"firstName": "",
"lastName": "",
"fullNumber": "",
"cvv": "",
"expirationMonth": "",
"expirationYear": "",
"billingZip": ""
},
"customerAttributes": {
"firstName": "",
"lastName": "",
"email": "[email protected]",
"phone": "",
"organization": "44a18ce7b0",
"reference": "[email protected]"
},
"productHandle": "coreweave-cloud",
"reference": "tenant-ef1b7290f0"
}
}
Am I missing something obvious here?
@BryceBeagle @jkimbo maybe you guys can grok what I'm doing wrong?
@mecampbellsoup I've tried this with both starlette and django, it seems to be working fine.
maybe there's something in your resolver that's causing the issue? or do you have a custom django view?
@patrick91 here is my resolver:
@strawberry.type
class APIResponse:
ok: bool
errors: List[Optional[Error]]
@strawberry.type
class Mutation:
@strawberry.mutation
async def subscribe(self, info: Info, form: SubscriptionForm) -> APIResponse:
form_data = form
base_url = os.getenv('CHARGIFY_API_URL')
async with httpx.AsyncClient(base_url=base_url) as client:
api_key = os.getenv('CHARGIFY_API_KEY')
auth_str = base64.b64encode(f'{api_key}:x'.encode('utf-8')).decode('utf-8')
headers = {
'Authorization': f'Basic {auth_str}',
'Content-Type': 'application/json'
}
resp: HttpxResponse = await client.post('/subscriptions.json', headers=headers, json=form_data)
status: int = resp.status_code
print(status)
body: dict = resp.json()
print(body)
oh yes, this is the line that's broken:
resp: HttpxResponse = await client.post('/subscriptions.json', headers=headers, json=form_data)
you can do instead (after importing dataclasses:
resp: HttpxResponse = await client.post('/subscriptions.json', headers=headers, json=dataclasses.asdict(form_data))
OMG, thank you so much Patrick!!
How did you know that was the issue? Is this something I could add to the docs?
OMG, thank you so much Patrick!!
How did you know that was the issue? Is this something I could add to the docs?
I've seen that error a few times :) but I think also we haven't really documented well the fact that we can convert strawberry types to dicts with dataclasses.asdict
(it's implicit by the fact we use dataclasses). I wonder if we can do something better here (we could have our own asdict function or maybe a method on the types as well) 🤔
We might just want to implement our own JSONEncoder
that knows how to deal with Strawberry types
@BryceBeagle do you prefer that to converting types to dicts?
Probably, but only marginally
Converting things to dicts might retain types like dates and so on, which might be useful in somecases (also it should be faster than converting things to json all the time).
But here, the use case is explicitly for json, so I think it would be best to do the recursive conversion all the way down the object tree
But here, the use case is explicitly for json, so I think it would be best to do the recursive conversion all the way down the object tree
httpx will do the actual json conversion here: https://github.com/encode/httpx/blob/a3eb0f99dc112fb5b09c7d6fdb9d211f96a6e3c1/httpx/_content.py#L175
the json parameter expects a dict to be converted to json 😊
#2170