APPROACH 3: JSON Response Handling with FastLED's ideal JSON API This demonstrates fetch responses with automatic JSON parsing
| 219 | /// APPROACH 3: JSON Response Handling with FastLED's ideal JSON API |
| 220 | /// This demonstrates fetch responses with automatic JSON parsing |
| 221 | void test_json_response() { |
| 222 | FL_WARN("APPROACH 3: JSON Response handling with fl::json integration"); |
| 223 | |
| 224 | // TUTORIAL: Fetch a JSON API endpoint (httpbin.org provides test JSON) |
| 225 | // This endpoint returns JSON with request information |
| 226 | fl::net::http::fetch_get("https://httpbin.org/json").then([](const fl::net::http::Response& response) { |
| 227 | if (response.ok()) { |
| 228 | FL_WARN("SUCCESS [JSON Promise] HTTP fetch successful! Status: " |
| 229 | << response.status() << " " << response.status_text()); |
| 230 | |
| 231 | // TUTORIAL: Check if response contains JSON content |
| 232 | // is_json() checks Content-Type header and body content |
| 233 | if (response.is_json()) { |
| 234 | FL_WARN("DETECTED [JSON Promise] Response contains JSON data"); |
| 235 | |
| 236 | // TUTORIAL: response.json() returns fl::json with FastLED's ideal API |
| 237 | // Automatic parsing, caching, and safe access with defaults using operator| |
| 238 | fl::json data = response.json(); |
| 239 | |
| 240 | // TUTORIAL: Safe JSON access with defaults - never crashes! |
| 241 | // Uses FastLED's proven pattern: json["path"]["to"]["key"] | default_value |
| 242 | fl::string slideshow_url = data["slideshow"]["author"] | fl::string("unknown"); |
| 243 | fl::string slideshow_title = data["slideshow"]["title"] | fl::string("untitled"); |
| 244 | int slide_count = data["slideshow"]["slides"].size(); |
| 245 | |
| 246 | FL_WARN("JSON [Promise] Slideshow Author: " << slideshow_url); |
| 247 | FL_WARN("JSON [Promise] Slideshow Title: " << slideshow_title); |
| 248 | FL_WARN("JSON [Promise] Slide Count: " << slide_count); |
| 249 | |
| 250 | // TUTORIAL: Access nested arrays safely |
| 251 | if (data.contains("slideshow") && data["slideshow"].contains("slides")) { |
| 252 | fl::json slides = data["slideshow"]["slides"]; |
| 253 | if (slides.is_array() && slides.size() > 0) { |
| 254 | // Get first slide information with safe defaults |
| 255 | fl::string first_slide_title = slides[0]["title"] | fl::string("no title"); |
| 256 | fl::string first_slide_type = slides[0]["type"] | fl::string("unknown"); |
| 257 | FL_WARN("JSON [Promise] First slide: " << first_slide_title << " (" << first_slide_type << ")"); |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | // Visual feedback: Blue LEDs for successful JSON parsing |
| 262 | fill_solid(leds, NUM_LEDS, fl::CRGB(0, 0, 128)); // Blue for JSON success |
| 263 | |
| 264 | } else { |
| 265 | FL_WARN("INFO [JSON Promise] Response is not JSON format"); |
| 266 | // Visual feedback: Yellow for non-JSON response |
| 267 | fill_solid(leds, NUM_LEDS, fl::CRGB(64, 64, 0)); // Yellow for non-JSON |
| 268 | } |
| 269 | } else { |
| 270 | FL_WARN("ERROR [JSON Promise] HTTP error: " << response.status() |
| 271 | << " " << response.status_text()); |
| 272 | // Visual feedback: Red LEDs for HTTP error |
| 273 | fill_solid(leds, NUM_LEDS, fl::CRGB(64, 0, 0)); // Red for HTTP error |
| 274 | } |
| 275 | }).catch_([](const fl::task::Error& error) { |
| 276 | FL_WARN("ERROR [JSON Promise] Network error: " << error.message); |
| 277 | // Visual feedback: Purple LEDs for network error |
| 278 | fill_solid(leds, NUM_LEDS, fl::CRGB(64, 0, 64)); // Purple for network error |
no test coverage detected