fastly / fastly-py

A Fastly API client for Python
https://pypi.org/project/fastly/
MIT License
76 stars 59 forks source link

Python Boolean values are not understood by the API #93

Open Markb1337 opened 11 months ago

Markb1337 commented 11 months ago

Version

4.0.0 (and 3.x.x)

TLDR I am running into a bug with regards to Boolean values.

The bug seems to be in the way data is send to the API by the Fastly-py library, not necessarily in the API itself. The REST calls where this issue arises are of Content-Type ‘application/x-www-form-urlencoded’. The given values are transferred to the server 1:1. This means that when I provide a Python Boolean (i.e. False or True) for a certain parameter, it is sent as such to the API, although the API only seems to understand lowercase Boolean values, or binary values such as 0 or 1.

What I did I stumbled upon this bug while trying to create objects with specific parameters of type ‘Boolean’, in my case a backend object for my service with specific values for ‘ssl_check_cert’ and ‘use_ssl’.

My code does the following:

What I expected would happen I expected a service would be created, with a backend which has both 'ssl_check_cert' and 'use_ssl' set to False.

What actually happened I noticed that the values given in my Python code were not reflected in the created backend object. The values for both 'ssl_check_cert' and 'use_ssl' were set to True (the default value), completely ignoring my values during creation.

This behavior indicates that the given values are not understood by the Fastly API.

Extra comment

I’m not a programmer so I don’t know the best solution for this. I did however find a dirty hack which worked for me as a temporarily solution. I noticed this ‘_urlencode’ function in a very old version of the fastly-py project (0.5.x), which says something about converting Boolean to lowercase:

https://github.com/fastly/fastly-py/blob/1d3235611627811d83990c31a928e7cf21fe2caa/fastly/models.py#L31C1-L42C11

I somewhat recreated this function as follows:

def sanitize_list_of_tuples(input_list):
    def sanitize_value(value):
        """ Sanitize the value """
        if isinstance(value, bool):
            # Perform the desired conversion for booleans
            return int(value)  # Example: Convert boolean to integer
        # Handle other value types if needed
        return value

    sanitized_list = []
    for key, value in input_list:
        sanitized_value = sanitize_value(value)
        sanitized_list.append((key, sanitized_value))

    return sanitized_list

I added this function at the top of rest.py and added the following line before line 161 of rest.py:

post_params = sanitize_list_of_tuples(post_params)

This results in Boolean values being converted to their integer/binary representation, which the Fastly API does interpret correctly.

As I said, I’m not sure if this is the best solution, probably not, you guys probably know a better way to fix this issue across the board.

Let me know if you need any further information or assistance! Thanks in advance, Mark

Integralist commented 11 months ago

Thanks @Markb1337 for showing your workaround, very much appreciated.

I don't think this solution would be safe to apply generally (e.g. for all booleans) as not all fields that are boolean need to be coerced to an integer.

I checked in our manually curated go-fastly API client and we have a CBool type for handling this exact conversion between a bool and an integer, but it's not implemented for all booleans.

Meaning we'll need to figure out a way to identify this in our OpenAPI schema using a custom extension (e.g. x-bool-to-int) so that the code-generated API clients can implement the normalisation logic as you've implemented.

I'm going to create an internal ticket to track this and I'll provide feedback once I've had a chance to investigate further.

Thanks again for your help and patience.