Is this the best way to handle simple Ubidots Webhook Responses?

All,

I have read LukeUSMC (Semper Fi brother!) excellent tutorial.

I know I can use a webhook response template to parse the response from Ubidots but it seems like overkill as the JSON I get back from Ubidots is simply this:

{
“battery”: [{“status_code”:201}]
“hourly”: [{“status_code”:201}]
“temp”: [{“status_code”:201}]
“daily”: [{“status_code”:201}]
}
note: the order in which the variables are listed can vary.

I know I could create a response template to separate these values with tildes but it seems the biggest advantage of the response template is reducing the size of the data that needs to be transmitted to the Electron and this response is already short.

For my purposes, I am only interested in the response code that is associated with “hourly”. I came up with the code below which works but, if there is a better way or if I should reconsider response templates, I am all ears. Thank you.

void myHandler(const char *event, const char *data)
{
  Serial.println(data);
  if (!data) {              // First check to see if there is any data
    Serial.print("No data returned from WebHook ");
    Serial.println(event);
    return;
  }
  String response = data;   // If there is data - copy it into a String variable
  int datainResponse = response.indexOf("hourly") + 24; // Find the "hourly" field and add 24 to get to the value
  String responseCodeString = response.substring(datainResponse,datainResponse+3);  // Trim all but the value
  int responseCode = responseCodeString.toInt();  // Put this into an int for comparisons
  switch (responseCode) {   // From the Ubidots API refernce https://ubidots.com/docs/api/#response-codes
    case 200:
      Serial.println("Request successfully completed");
    case 201:
      Serial.println("Successful request - new data point created");
      break;
    case 400:
      Serial.println("Bad request - check JSON body");
      break;
    case 403:
      Serial.println("Forbidden token not valid");
      break;
    case 404:
      Serial.println("Not found - verify variable and device ID");
      break;
    case 405:
      Serial.println("Method not allowed for API endpoint chosen");
      break;
    case 501:
      Serial.println("Internal error");
      break;
    default:
      Serial.print("Ubidots Response Code: ");    // Non-listed code - generic response
      Serial.println(responseCode);
      break;
  }
}

It is a personal preference sometimes. Are you planning to parse more JSON in the future? In the Particle IDE, I have worked with the JsonStreamingParser (1.0.5). It needs a small change to be re-usable as a global variable. The other issue is you will need to create different “listener” classes to deal with different JSON structures/responses. I can see it possibly being useful here if your planning to do other JSON parsing.

Here is some sample code. The JSON above isn’t quite formatted correctly and caused a little bit of head banging until I realized the commas were missing. I tweaked the JsonStreamingParser ever so slightly to allow the object to be re-used with new strings.

When all is said and done, it pulls out the response you need. This opens up the avenue to pull out whatever parts you need. I included the bad response just so you see what the library does with badly behaved JSON.

0000013573 [app] INFO: System version: 0.6.2
0000013573 [app] INFO: ** TEST PARSE GOOD MESSAGE #1
0000013573 [app] INFO: start document
0000013574 [app] INFO: start object
0000013574 [app] INFO: start array: battery
0000013574 [app] INFO: start object
0000013574 [app] INFO: key: status_code value: 201
0000013575 [app] INFO: end object
0000013575 [app] INFO: end array
0000013575 [app] INFO: start array: hourly
0000013575 [app] INFO: start object
0000013575 [app] INFO: key: status_code value: 201
0000013576 [app] INFO: end object
0000013576 [app] INFO: end array
0000013576 [app] INFO: start array: temp
0000013576 [app] INFO: start object
0000013576 [app] INFO: key: status_code value: 201
0000013577 [app] INFO: end object
0000013577 [app] INFO: end array
0000013577 [app] INFO: start array: daily
0000013577 [app] INFO: start object
0000013577 [app] INFO: key: status_code value: 201
0000013578 [app] INFO: end object
0000013578 [app] INFO: end array
0000013578 [app] INFO: end object
0000013578 [app] INFO: end document
0000013578 [app] INFO: Hourly status code: 201
0000013579 [app] INFO: ** TEST PARSE GOOD MESSAGE #2
0000013579 [app] INFO: start document
0000013579 [app] INFO: start object
0000013579 [app] INFO: start array: battery
0000013580 [app] INFO: start object
0000013580 [app] INFO: key: status_code value: 201
0000013580 [app] INFO: end object
0000013580 [app] INFO: end array
0000013581 [app] INFO: start array: hourly
0000013581 [app] INFO: start object
0000013581 [app] INFO: key: status_code value: 500
0000013581 [app] INFO: end object
0000013581 [app] INFO: end array
0000013582 [app] INFO: start array: temp
0000013582 [app] INFO: start object
0000013582 [app] INFO: key: status_code value: 201
0000013582 [app] INFO: end object
0000013582 [app] INFO: end array
0000013583 [app] INFO: start array: daily
0000013583 [app] INFO: start object
0000013583 [app] INFO: key: status_code value: 201
0000013583 [app] INFO: end object
0000013584 [app] INFO: end array
0000013584 [app] INFO: end object
0000013584 [app] INFO: end document
0000013584 [app] INFO: Hourly status code: 500
0000013584 [app] INFO: ** TEST PARSE BAD MESSSAGE
0000013585 [app] INFO: start document
0000013585 [app] INFO: start object
0000013585 [app] INFO: start array: battery
0000013585 [app] INFO: start object
0000013586 [app] INFO: key: status_code value: 201
0000013586 [app] INFO: end object
0000013586 [app] INFO: end array
0000013586 [app] INFO: end object
0000013586 [app] INFO: end document
0000013587 [app] INFO: start document
0000013587 [app] INFO: start array: 
0000013587 [app] INFO: start object
0000013587 [app] INFO: key: status_code value: 201
0000013587 [app] INFO: end object
0000013588 [app] INFO: end array
0000013588 [app] INFO: end document
0000013588 [app] INFO: start document
0000013588 [app] INFO: start array: 
0000013588 [app] INFO: start object
0000013588 [app] INFO: key: status_code value: 201
0000013589 [app] INFO: end object
0000013589 [app] INFO: end array
0000013589 [app] INFO: end document
0000013589 [app] INFO: Hourly status code: 500
1 Like

@cermak,

Wow, thank you. I guess the question is as you said, how often do I intent to parse JSON. I need to spend some time learning about C++ Object as I am used to Wiring.

Am I right in assuming that your approach was required since this is a non-standard JSON format?

Again, thank you for taking the time to help me get my head around this.

Chip

Wait a minute, are you saying the response is non-JSON? What generates that response? [Edit: in your original post you say it is a JSON response, it actually isn’t - it is missing commas after each line]

The library I showed wants a well formed JSON response.

Well, I was trying to figure out how to specify the value I wanted and tried this on-line JSON viewer which was linked in another post in the forum: http://jsonviewer.stack.hu/

It said this was not properly formatted JSON. It was only happy once I added commas between the fields.

Did I get this wrong?

Chip

If your code is working, then your fine.

The proper looking JSON should be:

{
"battery": [{"status_code":201}],
"hourly": [{"status_code":201}],
"temp": [{"status_code":201}],
"daily": [{"status_code":201}],
}

I have the above as example in the demonstration code as well as what you had in the original post so you can see what happens to the parser.

Got it. I want to learn how to do this parsing so will play with your code. Thanks again.