Acknowledged
over 1 year ago

BUG: makeWebRequest POST omits nested parameters in wifi mode

1. Through the Music Player > Sync Menu, the watch starts looking for WIFI, then shows the menu. From here, nested parameters are omitted.
2. Through the Music Player > Library Menu, the watch uses the BLE to perform webrequests. From here, nested parameters are included without issue.
3. During sync, nested parameters seem to be omitted.
4. In simulator, nested parameters seem to be omitted during sync.

The following code as a minimal example:

var parameters = {
    "properties" => {
        "prop1" => "value 1",
        "etc." => "etc.",
    },
    "top" => "value"
};

var options = {
    :method => Communications.HTTP_REQUEST_METHOD_POST,
    :headers => {
        "Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
    },
    :responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON,
};

Communications.makeWebRequest(url, parameters, options, method(:onResponse));

The nested "properties" values get omitted by the webrequest, whereas top level properties like "top" => "value" are sent correctly. Tested on Vivoactive 4s, the nested properties are omitted when the menu is opened from the sync menu (after 'searching for wifi'). When the menu is opened from the Music Player > Library, and thus not connected to wifi, the nested properties are sent correctly, as well as the top level properties.

Parents
  • Addition: the nested parameter omission as described above occurs on ALL DEVICES seen until now.

    Found a workaround by accident. I was implementing a fix to flatten the property tree recursively, then send the information through a custom API endpoint. While implementing and testing this, I found that starting with a copy and then adding the flattened properties resulted in a complete property tree sent through wifi. I tried to isolate the solution by removing the line where flattened properties are added, but it immediately omits the nested properties over wifi again. I would guess it is related to object references being differently handled for requests over wifi, but I cannot debug any further than this.

    The flatten and copy code I am using that circumvents the issue:

    using Toybox.Lang;
    
    function copy(dict as Lang.Dictionary) as Lang.Dictionary {
    	var ret = {};
    	for (var idx = 0; idx < dict.keys().size(); ++idx) {
    		var key = dict.keys()[idx];
    		ret.put(key, dict.get(key));
    	}
    	return ret;
    }
    
    function merge(dict as Lang.Dictionary, dict2 as Lang.Dictionary) as Lang.Dictionary {
    	var ret = copy(dict);
    	var keys = dict2.keys();
    	for (var idx = 0; idx != keys.size(); ++idx) {
    		var key = keys[idx];
    		ret.put(key, dict2.get(key));
    	}
    	return ret;
    }
    
    function flat(prev as Lang.Object, dict as Lang.Dictionary) {
    	var ret = {};
    	var keys = dict.keys();
    	for (var idx = 0; idx != keys.size(); ++idx) {
    		var key = keys[idx];
    		var value = dict.get(key);
    		var new_key = prev + "." + key;
    		if (value instanceof Lang.Dictionary) {
    			ret = merge(ret, flat(new_key, value));
    		} else {
    			ret.put(new_key, value);
    		}
    	}
    	return ret;
    }
    
    function flatten(dict as Lang.Dictionary) {
    	var ret = copy(dict);
    	var keys = dict.keys();
    	for (var idx = 0; idx != keys.size(); ++idx) {
    		var key = keys[idx];
    		var value = dict.get(key);
    		if (value instanceof Lang.Dictionary) {
    			ret = merge(ret, flat(key, value));
    		} else {
    			ret.put(key, value);
    		}
    	}
    	return ret;
    }

    Then, right before the Communications.makeWebRequest, call the flatten method:

    parameters = flatten(parameters);

    Hope this helps anyone else running into this bug and/or helps in tracking down and solving the bug!

Comment
  • Addition: the nested parameter omission as described above occurs on ALL DEVICES seen until now.

    Found a workaround by accident. I was implementing a fix to flatten the property tree recursively, then send the information through a custom API endpoint. While implementing and testing this, I found that starting with a copy and then adding the flattened properties resulted in a complete property tree sent through wifi. I tried to isolate the solution by removing the line where flattened properties are added, but it immediately omits the nested properties over wifi again. I would guess it is related to object references being differently handled for requests over wifi, but I cannot debug any further than this.

    The flatten and copy code I am using that circumvents the issue:

    using Toybox.Lang;
    
    function copy(dict as Lang.Dictionary) as Lang.Dictionary {
    	var ret = {};
    	for (var idx = 0; idx < dict.keys().size(); ++idx) {
    		var key = dict.keys()[idx];
    		ret.put(key, dict.get(key));
    	}
    	return ret;
    }
    
    function merge(dict as Lang.Dictionary, dict2 as Lang.Dictionary) as Lang.Dictionary {
    	var ret = copy(dict);
    	var keys = dict2.keys();
    	for (var idx = 0; idx != keys.size(); ++idx) {
    		var key = keys[idx];
    		ret.put(key, dict2.get(key));
    	}
    	return ret;
    }
    
    function flat(prev as Lang.Object, dict as Lang.Dictionary) {
    	var ret = {};
    	var keys = dict.keys();
    	for (var idx = 0; idx != keys.size(); ++idx) {
    		var key = keys[idx];
    		var value = dict.get(key);
    		var new_key = prev + "." + key;
    		if (value instanceof Lang.Dictionary) {
    			ret = merge(ret, flat(new_key, value));
    		} else {
    			ret.put(new_key, value);
    		}
    	}
    	return ret;
    }
    
    function flatten(dict as Lang.Dictionary) {
    	var ret = copy(dict);
    	var keys = dict.keys();
    	for (var idx = 0; idx != keys.size(); ++idx) {
    		var key = keys[idx];
    		var value = dict.get(key);
    		if (value instanceof Lang.Dictionary) {
    			ret = merge(ret, flat(key, value));
    		} else {
    			ret.put(key, value);
    		}
    	}
    	return ret;
    }

    Then, right before the Communications.makeWebRequest, call the flatten method:

    parameters = flatten(parameters);

    Hope this helps anyone else running into this bug and/or helps in tracking down and solving the bug!

Children
No Data