1182  REST API Design: Worked Examples and Practice

1182.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Design RESTful IoT APIs: Apply REST constraints to IoT resource hierarchies
  • Implement Proper Error Handling: Use HTTP status codes correctly for device states
  • Handle Offline Devices: Design APIs that gracefully handle connectivity issues
  • Apply Protocol Selection: Choose between CoAP, MQTT, and HTTP for different scenarios
  • Calculate Protocol Overhead: Understand the impact of protocol choice on battery life

1182.2 Prerequisites

Before diving into this chapter, you should be familiar with:

1182.3 How This Chapter Fits

REST API Design Series Navigation: 1. Introduction and Why Lightweight Protocols Matter 2. Protocol Overview and Comparison 3. REST API Design for IoT (Index) - Design Patterns - Worked Examples and Quizzes (this chapter) 4. Real-time Protocols 5. Protocol Selection Worked Examples

This chapter provides hands-on practice with REST API design through worked examples and comprehensive quizzes.


1182.4 Worked Examples: REST API Design for IoT

These worked examples demonstrate practical REST API design decisions for real-world IoT scenarios.

NoteWorked Example: Designing a Smart Thermostat REST API

Scenario: You are building a REST API for a smart thermostat system that allows mobile apps to read current temperature, set target temperature, and retrieve historical data. The system has 500 deployed thermostats.

Given: - Thermostat reports temperature every 30 seconds - Users want real-time display and control from mobile app - Historical data retention: 30 days - Expected concurrent mobile app users: 2,000

Steps:

  1. Define resource hierarchy - Organize resources around the device:

    /api/v1/thermostats/{device_id}              # Device info
    /api/v1/thermostats/{device_id}/temperature  # Current reading
    /api/v1/thermostats/{device_id}/setpoint     # Target temperature
    /api/v1/thermostats/{device_id}/history      # Historical readings
  2. Choose HTTP methods for each operation:

    • GET /thermostats/thermo-42/temperature - Read current temp (idempotent)
    • PUT /thermostats/thermo-42/setpoint - Set target (full update, idempotent)
    • GET /thermostats/thermo-42/history?start=2025-01-01&end=2025-01-15 - Query with filters
  3. Design response format with proper status codes:

    // GET /thermostats/thermo-42/temperature
    // Response: 200 OK
    {
      "device_id": "thermo-42",
      "current_temp_c": 22.5,
      "humidity_pct": 45,
      "timestamp": "2025-01-15T10:30:00Z",
      "unit": "celsius"
    }
    
    // PUT /thermostats/thermo-42/setpoint with body {"target_c": 21.0}
    // Response: 200 OK (or 204 No Content)
    {
      "device_id": "thermo-42",
      "target_c": 21.0,
      "estimated_time_minutes": 15
    }
    
    // GET /thermostats/nonexistent/temperature
    // Response: 404 Not Found
    {
      "error": "DEVICE_NOT_FOUND",
      "message": "Device 'nonexistent' is not registered",
      "timestamp": "2025-01-15T10:30:00Z"
    }

Result: A clean, RESTful API with predictable endpoints, proper HTTP semantics, and clear error handling. The hierarchy /thermostats/{id}/resource scales to thousands of devices while remaining intuitive for developers.

Key Insight: REST API design should follow the principle of resource-oriented design - model your API around nouns (thermostat, temperature, setpoint) not verbs (getTemperature, setTarget). The HTTP methods (GET, PUT, POST, DELETE) provide the verbs. This makes the API self-documenting and consistent across all resources.


NoteWorked Example: Handling Device Offline State in REST APIs

Scenario: A fleet management system has 1,000 GPS trackers on delivery trucks. Some trucks lose cellular connectivity in remote areas. Your REST API must handle requests for offline devices gracefully without confusing mobile app users.

Given: - GPS trackers report location every 60 seconds when connected - Some trucks go offline for hours in low-coverage areas - Mobile dispatch app needs last known location even when device is offline - App users must clearly understand device connectivity status

Steps:

  1. Define “offline” threshold and track last-seen timestamp:

    OFFLINE_THRESHOLD_SECONDS = 180  # 3 minutes without heartbeat
    
    def is_device_online(device_id):
        last_seen = get_last_heartbeat(device_id)
        age_seconds = (now() - last_seen).total_seconds()
        return age_seconds < OFFLINE_THRESHOLD_SECONDS
  2. Include connectivity metadata in every response:

    // GET /api/v1/vehicles/truck-42/location
    // Response: 200 OK (even if offline - we have cached data)
    {
      "vehicle_id": "truck-42",
      "latitude": 37.7749,
      "longitude": -122.4194,
      "speed_kmh": 0,
      "heading_degrees": 90,
      "timestamp": "2025-01-15T08:15:00Z",
      "connectivity": {
        "status": "offline",
        "last_seen": "2025-01-15T08:15:00Z",
        "offline_duration_minutes": 135
      }
    }
  3. Use appropriate HTTP status codes for different scenarios:

    @app.route('/api/v1/vehicles/<vehicle_id>/location')
    def get_location(vehicle_id):
        vehicle = db.get_vehicle(vehicle_id)
    
        if not vehicle:
            # Device never registered
            return {"error": "VEHICLE_NOT_FOUND"}, 404
    
        location = cache.get_last_location(vehicle_id)
    
        if not location:
            # Device registered but never reported location
            return {"error": "NO_LOCATION_DATA",
                    "message": "Device has not reported location yet"}, 404
    
        # Return cached location with connectivity status
        # Use 200 OK - we have valid data, just stale
        return {
            "vehicle_id": vehicle_id,
            "latitude": location.lat,
            "longitude": location.lng,
            "timestamp": location.timestamp.isoformat(),
            "connectivity": get_connectivity_status(vehicle_id)
        }, 200

Result: The API returns 200 OK with the last known location and explicit connectivity metadata, allowing the mobile app to display “Last seen 2 hours ago at [location]” rather than showing an error. The 404 status is reserved for truly missing resources (unknown vehicle ID).

Key Insight: For IoT REST APIs, distinguish between “no data” and “stale data”. A device being offline is not an error condition - it’s expected state information. Return cached/stale data with metadata about freshness rather than failing with 503 Service Unavailable. This keeps mobile apps functional even with intermittent device connectivity.


1182.5 Key Takeaways

NoteSummary

Core Concepts: - Application protocols define how IoT devices exchange data: MQTT (publish-subscribe), CoAP (request-response), HTTP (universal REST), AMQP (enterprise queuing) - MQTT uses persistent TCP connections with 2-byte headers and QoS levels (0/1/2) for scalable telemetry from many devices to cloud - CoAP provides RESTful operations (GET/POST/PUT/DELETE) over UDP with 4-byte headers, ideal for constrained devices and direct queries - Protocol selection depends on communication pattern (one-to-one vs many-to-many), power constraints, and reliability requirements

Practical Applications: - Smart home systems: MQTT broker manages devices/apps with topic-based publish-subscribe (temperature/bedroom, lights/kitchen) - Battery sensors: CoAP minimizes overhead with connectionless UDP requests, avoiding TCP’s keep-alive energy drain - Hybrid architectures: CoAP for edge sensor-to-gateway communication, MQTT for gateway-to-cloud distribution (leverages both strengths) - Web integration: HTTP remains standard for mobile apps and browsers connecting to IoT gateways or cloud APIs

Design Considerations: - Choose MQTT when multiple subscribers need device data (dashboards, analytics, alerts all subscribe to sensor topics) - Choose CoAP for direct device queries with minimal overhead (checking current status, firmware version polling) - MQTT broker becomes single point of failure requiring high availability and proper client reconnection logic - CoAP’s UDP transport requires application-layer reliability through Confirmable messages for critical operations

Common Pitfalls: - Using HTTP for thousands of battery sensors (100+ byte headers waste bandwidth and energy vs CoAP’s 4 bytes) - Assuming MQTT’s publish-subscribe always better than CoAP (request-response pattern more efficient for on-demand queries) - Forgetting MQTT persistent connections require keep-alive packets that drain batteries every few minutes - Not considering broker capacity limits when scaling MQTT deployments (10,000+ sensors may overwhelm single broker instance)


1182.6 Quiz: Comprehensive Protocol Review

Question: A battery-powered soil moisture sensor wakes every 6 hours, sends a 15-byte reading to a gateway 50 meters away using IEEE 802.15.4 radio (250 kbps max), then immediately sleeps. The sensor’s 1000 mAh battery must last 2 years minimum. Gateway then forwards data to cloud using Wi-Fi. Comparing CoAP over UDP vs MQTT over TCP, which protocol saves more battery life and by how much?

Explanation: This demonstrates protocol overhead impact on battery-powered IoT devices:

From the text - Why Lightweight Protocols:

IoT Environment Constraints: - Limited processing power (8-bit to 32-bit microcontrollers) - Constrained memory (KB not GB) - Low bandwidth networks (often < 250 kbps) - Battery-powered operation (months to years) - Unreliable wireless connections”

Detailed Power Consumption Analysis:

The chapter compares three protocol choices for a sensor that transmits once every 6 hours, using a 1000 mAh battery.

  • CoAP over UDP (optimal choice):
    • Active energy per cycle: 0.00267 mAh
    • 4 cycles per day, Total daily consumption: approximately 0.0347 mAh/day
    • Idealised battery life: approximately 79 years (realistically a few years once self-discharge and temperature are included).
  • MQTT over TCP (higher overhead):
    • Active energy per cycle: 0.00496 mAh
    • 4 cycles per day, Total daily consumption: approximately 0.0438 mAh/day
    • Idealised battery life: approximately 62.5 years.
  • HTTP over TCP (worst of the three):
    • Active energy per cycle: 0.00513 mAh
    • Total daily consumption: approximately 0.0445 mAh/day
    • Idealised battery life: approximately 61.6 years.

Battery life comparison summary:

Protocol Active time per day Bytes sent per cycle Idealised battery life Relative to MQTT
CoAP/UDP approx 0.86 s 26 bytes ~79 years ~27% longer
MQTT/TCP approx 0.13 s + overhead 239 bytes ~62.5 years baseline
HTTP/TCP approx 0.17 s + overhead 209 bytes ~61.6 years ~1-2% worse

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart LR
    subgraph comparison["Battery Life Comparison"]
        coap["CoAP/UDP<br/>2.5 years<br/>Exceeds by 25%"]
        mqtt["MQTT/TCP<br/>2.0 years<br/>Barely meets"]
        http["HTTP/TCP<br/>1.9 years<br/>Fails requirement"]
    end

    subgraph savings["CoAP Savings"]
        calc["vs MQTT: 25% improvement<br/>Real-world: ~40% better"]
    end

    coap --> calc

    style coap fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style mqtt fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
    style http fill:#7F8C8D,stroke:#2C3E50,stroke-width:2px,color:#fff
    style calc fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff

Figure 1182.1: Battery life comparison showing CoAP exceeds 2-year requirement while HTTP fails to meet it

Why CoAP Saves 40% Battery Life:

1. No TCP Handshake:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart TB
    subgraph mqtt["MQTT (TCP)"]
        m1["TCP Handshake<br/>180 bytes transmitted"]
    end

    subgraph coap["CoAP (UDP)"]
        c1["Connectionless<br/>0 bytes handshake"]
    end

    subgraph savings["Power Savings"]
        s1["180 bytes = 5.76 ms radio time"]
        s2["20 mA x 5.76 ms = 0.032 mAh/cycle"]
        s3["Over 2 years: 93.4 mAh saved"]
        s4["Result: 9.3% battery savings"]
    end

    mqtt --> savings
    coap --> savings
    s1 --> s2 --> s3 --> s4

    style m1 fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
    style c1 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style s4 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff

Figure 1182.2: TCP handshake comparison showing CoAP saves 9.3 percent battery by avoiding TCP connection overhead

2. Smaller Header Overhead:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart TB
    subgraph mqtt["MQTT/TCP Stack: 50 bytes"]
        m1["IP Header: 20 bytes"]
        m2["TCP Header: 20 bytes"]
        m3["MQTT Fixed: 2 bytes"]
        m4["MQTT Variable: 8 bytes"]
    end

    subgraph coap["CoAP/UDP Stack: 32 bytes"]
        c1["IP Header: 20 bytes"]
        c2["UDP Header: 8 bytes"]
        c3["CoAP Header: 4 bytes"]
    end

    subgraph result["Savings"]
        r1["18 bytes saved per message"]
        r2["Over 2 years: 52,560 bytes"]
        r3["Battery saved: ~15%"]
    end

    mqtt --> result
    coap --> result
    r1 --> r2 --> r3

    style m1 fill:#7F8C8D,stroke:#2C3E50,stroke-width:2px,color:#fff
    style m2 fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
    style c1 fill:#7F8C8D,stroke:#2C3E50,stroke-width:2px,color:#fff
    style c2 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style r3 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff

Figure 1182.3: Protocol header overhead comparison showing CoAP uses 32 bytes versus MQTT 50 bytes for 15 percent battery savings

3. Connection Setup/Teardown:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
sequenceDiagram
    participant C1 as MQTT Client
    participant S1 as MQTT Server
    participant C2 as CoAP Client
    participant S2 as CoAP Server

    rect rgb(230, 126, 34, 0.2)
        Note over C1,S1: MQTT/TCP: 8 packets
        C1->>S1: SYN
        S1->>C1: SYN-ACK
        C1->>S1: ACK
        C1->>S1: CONNECT
        S1->>C1: CONNACK
        C1->>S1: PUBLISH
        C1->>S1: FIN
        S1->>C1: FIN-ACK
    end

    rect rgb(22, 160, 133, 0.2)
        Note over C2,S2: CoAP/UDP: 2 packets
        C2->>S2: CON Request
        S2->>C2: ACK Response
    end

Figure 1182.4: Connection cycle comparison showing MQTT requires 8 packets while CoAP needs only 2 packets for 75 percent less radio time

4. Simplified State Machine:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart LR
    subgraph coap["CoAP: 3 States (Minimal RAM)"]
        C1((IDLE)) --> C2((SEND))
        C2 --> C3((WAIT_ACK))
        C3 --> C1
    end

    subgraph mqtt["MQTT/TCP: 8+ States (1-2 KB RAM)"]
        M1((IDLE)) --> M2((SYN_SENT))
        M2 --> M3((ESTABLISHED))
        M3 --> M4((MQTT_CONNECT))
        M4 --> M5((MQTT_CONNECTED))
        M5 --> M6((PUBLISH))
        M6 --> M7((FIN_WAIT))
        M7 --> M8((TIME_WAIT))
        M8 --> M1
    end

    subgraph result["Result"]
        R1["30% CPU savings<br/>Less complexity = Less power"]
    end

    coap --> result
    mqtt --> result

    style C1 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style C2 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style C3 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style M1 fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
    style R1 fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff

Figure 1182.5: State machine comparison showing CoAP uses 3 states versus MQTT 8 plus states for 30 percent CPU savings

Real-World Battery Life Calculation:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
mindmap
    root((Realistic<br/>Factors))
        Self-discharge
            2% per year
        Temperature
            -10% at cold temps
        ADC Sampling
            +0.1 mA average
        Sensor Reading
            +2 mA for 200 ms

Figure 1182.6: Realistic factors affecting battery life calculations in IoT deployments

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart TB
    subgraph coap["CoAP Daily Consumption"]
        p1["Protocol: 0.0107 mAh/day"]
        p2["Sleep: 0.024 mAh/day"]
        p3["ADC: 2.4 mAh/day"]
        p4["Sensor: 0.0056 mAh/day"]
        total["Total: 2.44 mAh/day"]
    end

    subgraph battery["With 1000 mAh Battery"]
        b1["410 days = 1.12 years"]
        b2["With self-discharge: ~1.0 year"]
        b3["Fails 2-year requirement!"]
    end

    subgraph solution["Solution: 3000 mAh Battery"]
        s1["CoAP: 3.37 years"]
        s2["MQTT: 3.34 years"]
        s3["HTTP: 3.33 years"]
    end

    p1 --> total
    p2 --> total
    p3 --> total
    p4 --> total
    total --> battery
    battery --> solution

    style total fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
    style b3 fill:#7F8C8D,stroke:#2C3E50,stroke-width:2px,color:#fff
    style s1 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff

Figure 1182.7: Daily consumption breakdown showing battery sizing requirements for 2-year deployment target

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart LR
    subgraph direct["Direct Savings"]
        d1["CoAP vs MQTT: 0.9%"]
    end

    subgraph additional["Additional Factors"]
        a1["Lower CPU wake time"]
        a2["No TCP buffer RAM"]
        a3["Lower-power radio modes"]
        a4["Less retransmission overhead"]
    end

    subgraph result["Real-World Result"]
        r1["CoAP: ~40% better<br/>battery efficiency"]
    end

    direct --> result
    additional --> result

    style r1 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff

Figure 1182.8: Real-world CoAP advantage accounting for additional efficiency factors beyond direct protocol savings

Why Other Options Are Wrong:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart TB
    subgraph optionA["Option A: MQTT saves 30% - WRONG"]
        a1["TCP connection overhead"]
        a2["CONNECT/CONNACK exchange"]
        a3["Connection teardown"]
        a4["Larger protocol stack"]
        a5["239 vs 26 bytes per cycle"]
        aResult["Result: MQTT uses 40% MORE battery"]
    end

    subgraph optionB["Option B: Equal battery - WRONG"]
        b1["Both lightweight vs HTTP"]
        b2["But CoAP has advantages:"]
        b3["+ Connectionless"]
        b4["+ Smaller headers"]
        b5["+ UDP vs TCP"]
        b6["+ Simpler state machine"]
        bResult["Measured: 40% savings with CoAP"]
    end

    subgraph optionD["Option D: HTTP saves most - WRONG"]
        d1["Text-based verbose headers"]
        d2["Requires TCP connection"]
        d3["No compression support"]
        d4["Not designed for IoT"]
        dResult["CoAP: 26 bytes vs HTTP: 209 bytes<br/>CoAP is 8x more efficient"]
    end

    style aResult fill:#7F8C8D,stroke:#2C3E50,stroke-width:2px,color:#fff
    style bResult fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style dResult fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff

Figure 1182.9: Analysis of why alternative protocol options are incorrect for battery-powered IoT sensors

Network Transmission Timing:

IEEE 802.15.4 @ 250 kbps:

CoAP message (26 bytes):
  26 bytes x 8 bits/byte / 250,000 bps = 0.832 ms
  Plus CSMA/CA backoff: ~2-5 ms
  Total radio time: ~6 ms

MQTT message (239 bytes including TCP/IP):
  239 bytes x 8 bits/byte / 250,000 bps = 7.65 ms
  Plus TCP handshake: 180 bytes = 5.76 ms
  Plus CSMA/CA backoff: ~10-15 ms
  Total radio time: ~23 ms

HTTP message (209 bytes):
  Similar to MQTT + larger headers
  Total radio time: ~25 ms

Radio power consumption dominates battery life
Shorter radio time = longer battery life
CoAP: 6 ms vs MQTT: 23 ms = 74% less radio time

Industry Deployment Example:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
mindmap
    root((Smart Agriculture<br/>Deployment))
        Requirements
            1000 soil moisture sensors
            Report every 6 hours
            2-year battery target
            IEEE 802.15.4 mesh
        Battery
            3000 mAh per sensor
            2x AA lithium

Figure 1182.10: Smart agriculture deployment requirements for protocol analysis

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart TB
    subgraph coap["CoAP/UDP - RECOMMENDED"]
        c1["Lifetime: 3.37 years"]
        c2["Cost: $38/sensor"]
        c3["Replacement visits: 0"]
        c4["Total: $38,000"]
    end

    subgraph mqtt["MQTT/TCP - Borderline"]
        m1["Lifetime: 3.34 years"]
        m2["Cost: $38/sensor"]
        m3["Barely exceeds 2 years"]
        m4["Total: $38,000"]
    end

    subgraph http["HTTP/TCP - Risky"]
        h1["Lifetime: 3.33 years"]
        h2["Cost: $38/sensor"]
        h3["May fail in cold weather"]
        h4["Total: $38,000 + risk"]
    end

    verdict["Verdict: CoAP provides best<br/>reliability margin"]

    coap --> verdict
    mqtt --> verdict
    http --> verdict

    style c1 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style m1 fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
    style h3 fill:#7F8C8D,stroke:#2C3E50,stroke-width:2px,color:#fff
    style verdict fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff

Figure 1182.11: Protocol cost analysis for 1000 sensor deployment comparing CoAP, MQTT, and HTTP

Conclusion:

For battery-powered sensors on IEEE 802.15.4 networks sending sporadic data: - CoAP over UDP: Optimal choice (40% battery savings) - Connectionless reduces handshake overhead - Smaller headers minimize radio time - Simpler protocol reduces CPU time - Designed for exactly this use case

MQTT better for: Always-connected devices, pub-sub patterns, reliable Wi-Fi/cellular CoAP better for: Battery-powered, sporadic transmission, constrained networks

This soil moisture sensor is the textbook use case for CoAP.

Question: A smart home system has a phone app that needs to directly query the current temperature from a thermostat and adjust its setpoint. The system also has a cloud dashboard subscribed to temperature updates from 5 thermostats in different rooms for historical logging. Which protocol architecture provides the most efficient solution?

Explanation: This demonstrates protocol selection based on communication patterns:

Communication Pattern Analysis:

Use Case 1: Phone to Thermostat (Direct Control)

Phone query: "What's the current temperature?"
Thermostat response: "22.5C"
Phone command: "Set temperature to 24C"
Thermostat response: "OK, setpoint updated"

Pattern: Request-Response
Frequency: Sporadic (user-initiated)
Participants: 1-to-1 (phone to specific thermostat)
Network: Local Wi-Fi (same network as thermostat)

Use Case 2: Thermostats to Cloud Dashboard (Monitoring)

5 thermostats publish updates every 5 minutes:
  thermostat/living_room -> {"temp": 22.5, "humidity": 45}
  thermostat/bedroom -> {"temp": 21.0, "humidity": 50}
  thermostat/kitchen -> {"temp": 23.5, "humidity": 48}
  thermostat/bathroom -> {"temp": 24.0, "humidity": 60}
  thermostat/garage -> {"temp": 18.5, "humidity": 55}

Dashboard subscribes to: thermostat/# (all thermostats)

Pattern: Publish-Subscribe
Frequency: Periodic (every 5 minutes)
Participants: Many-to-One (5 thermostats to 1 dashboard)
Network: Internet (cloud connection)

Option B: Hybrid CoAP + MQTT (Correct):

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#ecf0f1', 'noteTextColor': '#2C3E50', 'noteBkgColor': '#fff9e6', 'textColor': '#2C3E50', 'fontSize': '13px'}}}%%
graph TB
    subgraph Local["Local Network (CoAP)"]
        Phone["Phone App"] <-->|CoAP<br/>GET/POST<br/>Request-Response| Thermostat["Thermostat"]
    end

    subgraph Cloud["Cloud (MQTT)"]
        Thermostat -->|MQTT Publish<br/>thermostat/data<br/>Every 5 min| Broker["MQTT Broker"]
        Broker -->|MQTT Subscribe<br/>thermostat/#| Dashboard["Cloud Dashboard"]
    end

    style Local fill:#16A085,stroke:#16A085,color:#fff
    style Cloud fill:#E67E22,stroke:#D35400,color:#fff

Figure 1182.12: Hybrid CoAP Local Control with MQTT Cloud Reporting Architecture

Phone to Thermostat (CoAP) Benefits: - No broker needed (direct communication) - Low latency (local network, no internet round-trip) - Works offline (no internet required for local control) - RESTful semantics (GET/PUT familiar to developers) - Minimal overhead (4-byte CoAP header)

Thermostats to Cloud Dashboard (MQTT) Benefits: - One subscription receives data from all 5 thermostats - New thermostats automatically discovered (wildcard subscription) - Dashboard doesn’t need to know thermostat IPs - Retained messages provide last-known state - QoS 1 ensures reliable delivery to cloud

Performance Comparison:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart TB
    subgraph hybrid["Hybrid CoAP+MQTT - BEST"]
        h1["Latency: 20 ms local"]
        h2["Works offline: YES"]
        h3["Scalability: Excellent"]
        h4["Overhead: Minimal 4B+2B"]
        h5["Firmware: 40 KB"]
    end

    subgraph mqttonly["MQTT Only"]
        m1["Latency: 150 ms"]
        m2["Works offline: NO"]
        m3["Scalability: Excellent"]
        m4["Overhead: Medium 2B"]
        m5["Firmware: 45 KB"]
    end

    subgraph httpplus["HTTP+MQTT"]
        p1["Latency: 30 ms"]
        p2["Works offline: YES"]
        p3["Scalability: Excellent"]
        p4["Overhead: High 55B+2B"]
        p5["Firmware: 65 KB"]
    end

    verdict["Best for smart home: Hybrid CoAP+MQTT"]

    hybrid --> verdict
    mqttonly -.-> verdict
    httpplus -.-> verdict

    style h1 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style h2 fill:#16A085,stroke:#2C3E50,stroke-width:2px,color:#fff
    style m2 fill:#7F8C8D,stroke:#2C3E50,stroke-width:2px,color:#fff
    style p4 fill:#E67E22,stroke:#2C3E50,stroke-width:2px,color:#fff
    style verdict fill:#2C3E50,stroke:#16A085,stroke-width:2px,color:#fff

Figure 1182.13: Performance comparison of hybrid CoAP plus MQTT versus MQTT only versus HTTP plus MQTT for smart home systems

Why Other Options Are Wrong:

A: MQTT for both - MQTT is designed for publish-subscribe, not request-response. Using MQTT for phone-thermostat control requires awkward workarounds and cannot work offline (no internet = no broker = no local control).

C: CoAP for everything - Using CoAP Observe for dashboard monitoring requires managing separate connections for each thermostat. Adding new thermostats requires dashboard reconfiguration, unlike MQTT’s simple wildcard subscription.

D: HTTP REST for phone-thermostat - HTTP has larger overhead (55+ bytes vs CoAP’s 10 bytes) and requires a full HTTP server on the thermostat (40 KB flash vs 15 KB for CoAP).

Industry Best Practice:

For smart home systems: - Use CoAP for local device-to-device control (phone to devices) - Use MQTT for cloud monitoring and integration - Provides best user experience (offline control works) - Optimal protocol efficiency for each use case

Question 9: A factory needs real-time (<100ms) alerts from 200 pressure sensors. Network experiences 5% packet loss. Which protocol configuration is BEST?

Explanation: CoAP CON messages provide: (1) Reliability with retransmission (handles 5% loss), (2) Low latency - ACK within 20-50ms (meets <100ms requirement), (3) Minimal overhead. NON messages would lose 5% of critical alerts. MQTT QoS 2 has 4-way handshake (slower). HTTP polling wastes bandwidth and has higher latency.

Question 13: Calculate total overhead: Sending “25.3” (4 bytes) via CoAP over UDP/IPv4. What percentage is protocol overhead?

Explanation: Total packet: 4 (payload) + 4 (CoAP) + 8 (UDP) + 20 (IPv4) + 14 (Ethernet) = 50 bytes. Overhead = 46 bytes. Percentage = 46/50 = 92%. Answer C closest at 89%. This shows why IoT protocols optimize every byte - small payloads dominated by protocol overhead.


1182.7 Summary

This chapter provided hands-on practice with REST API design through worked examples:

Key topics covered: - Smart thermostat API design: Resource hierarchies, HTTP methods, status codes - Handling offline devices: Connectivity metadata, stale vs missing data distinction - Protocol overhead calculations: CoAP vs MQTT vs HTTP battery impact - Hybrid architecture patterns: CoAP for local control, MQTT for cloud telemetry

1182.8 What’s Next?

Continue exploring IoT application protocols:

For implementation details: - MQTT Fundamentals - CoAP Fundamentals and Architecture