%%{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
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:
- REST API Design Patterns: API design best practices, versioning, payload formats
- Protocol Overview and Comparison: Technical comparison of HTTP, MQTT, and CoAP
- HTTP Basics: Request methods (GET, POST, PUT, DELETE), status codes, headers
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.
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:
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 readingsChoose 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
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.
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:
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_SECONDSInclude 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 } }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
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
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:
- Design Patterns: API versioning, payload formats, rate limiting
- Real-time Protocols: VoIP, SIP, and RTP for audio/video IoT applications
- Protocol Selection Worked Examples: Agricultural sensor network case study
For implementation details: - MQTT Fundamentals - CoAP Fundamentals and Architecture