Strange http failure for simple json api call in driver

I'm hoping someone might be able to shed some light on this. I've searched all the topics I can find in and out of the forum but nothing seems to address this specific issue.

I'm calling a very simple json api on a local network device, and no matter how I do it I'm getting a null response to the query and the following parse failure exception message:

HTTP call failed: status code: 200, reason phrase: OK, groovyx.net.http.ResponseParseException: status code: 200, reason phrase: OK

My understanding is that the 200 response is correct and valid, and a curl execution of the same httpPost command from both Windows and linux hosts works correctly. It seems it's just the Hubitat http subsystem that is treating this as an error or seeing something it doesn't like in the response, but I can find no information about why this might be, or a way to try to debug further. Might this be a bug in the http method(s) (I've tried both httpPost and httpPostJson)?

The code snippet that generates this message is below. I've tried many different ways of making this request, all gleaned from working examples, all yield the same result.

    try {
        httpPostJson(params) { resp ->
            if (resp.success) {
                log.debug("Received HTTP response")
            }
            if (resp.data) {
                log.debug "${resp.data}"
                data = resp.data
                state.token = data.value.token
                log.debug "Token is ${state.token}"
            }
        }
    } catch (Exception e) {
        log.warn "HTTP call failed: ${e.message}, ${e.toString()}"
    }

Thanks in advance for any suggestions.

You talk about using a http put call in curl but are using a post in your groovy code, could that be the issue?

Sorry, typo in the post (fixed), I've tried Put as well but Post is what is normally used and works via curl commands.

1 Like

What are the contents of params for the request?

I'll bet it is responding with a 200 (success) but with text that describes it as a failure (like some HTML or a string) that can't be parsed as json.

Try just httpPost(params) and set the contentType parameter (if needed) to see if you can get a (less) auto-parsed response.

Thanks for the suggestion, unfortunately one of the first things I tried was to set contentType to plain text to try to see what the method was seeing being returned. The same parsing error occurs regardless of contentType set for the returned value.

From a successful curl command what is apparently being returned is the expected simple json:

{"token":"KjQgYnt+XysQakgQRxc/RQ==","result":false,"deviceStatus":"IDLE","data":{},"errors":[999]}

Nothing in that should obviously trip up parsing, and you'd expect it to be represented as the above string if the contentType was text, but the method always errors. Unless one of the 'result' or 'errors' values are reserved in some way and being interpreted as a failure? But curl doesn't do so.

as mentioned the return 200 means your call is ok.. but whatever is coming back is json so the parsing is failing. im guessing it cannot handle the blank {} in the middle of json..

you may have to just parse it yourself..

I wondered about the blank data values. The problem is I can't get access to the response to parse it myself, as the method always throws an exception and never populates the response variable. So I can't even see the response let alone manipulate it!

you have the results in your error case you can just check that it is 200 and ok and then parse it yourself.. and go on.. i have similiar issues in the teslafi api that shows failure but status is ok..

here is mine.. i can get the stuff in the error case

def params = [
    uri: "https://www.teslafi.com/feed.php" + "${path}",
    headers: [
        'Accept': 'application/json, text/javascript, */*; q=0.01', // */ comment
        'DNT': '1',
        'Accept-Encoding': 'gzip,deflate,sdch',
        'Cache-Control': 'max-age=0',
        'Accept-Language': 'en-US,en,q=0.8',
        'Connection': 'keep-alive',
        'Host': 'www.teslafi.com',
        'X-Requested-With': 'XMLHttpRequest',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36',
         Authorization: "Bearer ${teslaFiToken}"
        ]
]

 
if (debug) log.debug "command = $params"
def result = httpPostJson(params) { resp -> closure(resp) } 

 } catch (groovyx.net.http.HttpResponseException e) {
    	log.error "Request failed for path: ${path}.  ${e.response?.data}"  
    }

}

i think e.response.data.result should give you something given your comment above ..

That was the problem, the response was null no matter what and so I never had access to what was returned to be able to do anything with it.

However I just ran a test again using plain text as the contentType (which I'm sure threw the same parse exception previously) and this time it worked and I can get the json string and try to parse it. Not sure if something has changed (last time I tried was several firmware updates ago) or if I messed up when I tried this previously, but either way I can now see a way forward. Many thanks for the assistance everyone!

Also just checked and for json contentType the 'response' part of e.response.data.result is still null and not usable, but I should be able to go down the plain text route.

1 Like

For completeness I'll just document what the final resolution was:

Once I was able to see the actual text of the response it became apparent that the valid json was being preceded by some rubbish characters, which I hadn't noticed in the curl response due to a carriage return. Presumably the curl parser ignored these and picked up the valid json but the Hubitat parser (not unreasonably) was throwing an error.

It was then a simple matter to strip those extraneous characters and pass the now valid json to a slurper manually and extract the data I needed.

Thanks again everyone.

2 Likes

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.