moltin / python-sdk

Moltin python SDK
MIT License
6 stars 9 forks source link

JSON payload not being handled correctly #4

Open jordanmkoncz opened 8 years ago

jordanmkoncz commented 8 years ago

I've been getting an error response from the API (see https://github.com/moltin/issues/issues/22 for more info). After further testing I've found that the issue is being caused by the way the Moltin Python SDK is handling sending JSON payloads to the API.

In moltin.request.Request#post() the SDK is performing the call to the API using the Python Requests package by doing the following:

return with_error_handling(requests.post, request_url, data=payload, headers=headers)

The function it's calling is requests.api.post(url, data=None, json=None, **kwargs), and the issue is that the Moltin Python SDK is always passing the data parameter and never passing the json parameter. This means that when the Requests library gets to requests.models.PreparedRequest#prepare_body() it attempts to squash a payload that needs to be represented by JSON into POST parameters, which fails for nested JSON.

For example, let's say I'm trying to perform the following with the Moltin Pyton SDK:

order = cart.checkout({
    'bill_to': {
        'first_name': "Jon",
        'last_name': "Doe",
        'address_1': "123 Moltin Street",
        'city': "Mountain View",
        'county': "California",
        'country': "US",
        'postcode': "94040"
    },
    'ship_to': 'bill_to',
    'shipping': '1059477589212529113',
    'gateway': 'dummy'
})

Due to moltin.request.Request#post() passing this payload to requests.api.post() as the data parameter instead of the json parameter, the requests.models.PreparedRequest#prepare_body() function will turn this payload into the following:

'customer=1200342252304466230&ship_to=bill_to&shipping=1198234765833011342&bill_to=city&bill_to=first_name&bill_to=last_name&bill_to=country&bill_to=county&bill_to=address_1&bill_to=postcode&gateway=stripe'

Then the request to the API obviously fails since the bill_to provided to the API is completely invalid, and it returns a response of 'billing_address': ["Address 'postcode' not found"].

If the payload had instead been passed as the json parameter, the requests.models.PreparedRequest#prepare_body() function would have turned this payload into a JSON string and set the Content-Type header to application/json, and the request to the API would have been valid and worked.

I tried fixing this issue by simply updating moltin.request.Request#post() to always pass the payload as the json parameter instead of always passing it as the data parameter, but this caused the moltin.authenticate() function to fail. I think this happens because there's some code in the Moltin Python SDK that expects and relies on the payload being transformed into POST parameters instead of a JSON string.

I'm not experienced enough with Python or the code base of the Moltin Python SDK to see an easy fix for this issue but hopefully all this information will make it easy for one of the repository maintainers to fix it.