1181 REST API Design Patterns for IoT
1181.1 Learning Objectives
By the end of this chapter, you will be able to:
- Compare RESTful vs Message-Based Patterns: Choose between REST and pub-sub architectures
- Apply Topic and URI Naming Conventions: Design consistent MQTT topics and CoAP URIs
- Select Appropriate Payload Formats: Trade off between JSON, CBOR, and Protocol Buffers
- Implement API Versioning: Choose URI, header, or query parameter versioning strategies
- Apply Rate Limiting and Throttling: Protect infrastructure from device misbehavior
- Secure IoT APIs: Implement authentication, authorization, and TLS best practices
1181.2 Prerequisites
Before diving into this chapter, you should be familiar with:
- Introduction and Why Lightweight Protocols Matter: Understanding HTTP pitfalls in IoT
- Protocol Overview and Comparison: Technical comparison of HTTP, MQTT, and CoAP
- HTTP Basics: Request methods (GET, POST, PUT, DELETE), status codes, headers
1181.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 (this chapter) - Worked Examples and Quizzes 4. Real-time Protocols 5. Protocol Selection Worked Examples
This chapter focuses on practical REST API design patterns for IoT systems.
1181.4 IoT API Design Best Practices
Understanding protocol theory is essential, but practical API design determines whether your IoT system is maintainable, scalable, and developer-friendly. This section provides actionable guidance for designing IoT APIs using the protocols covered in this chapter.
Core Concept: REST (Representational State Transfer) defines six architectural constraints - client-server separation, statelessness, cacheability, uniform interface, layered system, and optional code-on-demand - that enable scalable, reliable web services.
Why It Matters: For IoT APIs, the statelessness constraint is critical: each request must contain all information needed to process it, with no server-side session state. This enables horizontal scaling (any server can handle any request), simplifies load balancing across regions, and allows devices to reconnect to different servers without losing context after network disruptions.
Key Takeaway: Design IoT REST APIs around resources (nouns like /devices/, /sensors/, /readings/) not actions (verbs like /getTemperature), and include authentication tokens in every request rather than relying on server sessions - this matches IoT reality where devices may connect through different gateways over time.
1181.4.1 RESTful vs Message-Based Patterns
The choice between REST (HTTP/CoAP) and message-based (MQTT) architectures fundamentally shapes your API design:
| Aspect | REST (HTTP/CoAP) | Message-Based (MQTT) |
|---|---|---|
| Pattern | Request-Response | Publish-Subscribe |
| State | Stateless | Connection-based |
| Discovery | URI paths | Topic hierarchy |
| Scalability | Horizontal (add servers) | Vertical (broker capacity) |
| Best For | CRUD operations, device control | Event streams, telemetry |
| Client Complexity | Simple (standard HTTP libs) | Moderate (manage subscriptions) |
Design principle: Use REST for commands and queries (“What is the temperature?”), use pub-sub for events and updates (“Temperature changed!”).
1181.4.2 Topic and URI Naming Conventions
Consistent naming prevents confusion in systems with thousands of devices:
1181.4.2.1 MQTT Topic Hierarchy
# Structure: {organization}/{location}/{building}/{floor}/{device_type}/{device_id}/{data_type}
# Examples:
acme/hq/bldg1/floor3/hvac/unit42/temperature
acme/factory/line2/sensor/pressure01/value
acme/warehouse/zone-a/motion/detector03/event
# Wildcards for subscriptions:
acme/hq/+/+/hvac/+/temperature # All HVAC temps in HQ
acme/+/+/+/motion/+/event # All motion events company-wide
Best practices: - Use lowercase, hyphens for readability - Start with organization/tenant for multi-tenant systems - Include location hierarchy for geographical filtering - End with data type (temperature, status, event, command) - Avoid special characters (/, +, #, $ reserved)
1181.4.2.2 CoAP URI Pattern
# Structure: coap://{host}/{version}/{resource_type}/{device_id}/{subresource}
# Examples:
coap://sensors.local/v1/devices/temp42/reading
coap://actuators.local/v1/devices/valve12/status
coap://gateway.local/v1/config/network
# Query parameters for filtering:
coap://sensors.local/v1/devices/temp42/history?start=2025-01-01&limit=100
Best practices: - Always version your API (/v1/, /v2/) to allow migration - Use plural resource names (/devices/, not /device/) - Keep URIs short (remember constrained bandwidth) - Use query parameters sparingly (adds overhead)
1181.5 Payload Format Selection
The right payload format balances human readability, efficiency, and tooling support:
| Format | Size | Human Readable | Schema Validation | Best For |
|---|---|---|---|---|
| JSON | Large (verbose) | Yes | JSON Schema | Development, debugging, web apps |
| CBOR | Small (binary) | No | CDDL | Constrained devices, low bandwidth |
| Protocol Buffers | Small (binary) | No | .proto files | High volume, multiple languages |
| MessagePack | Medium | No | None | Mixed environments |
| Plain Text | Variable | Yes | None | Simple sensors, legacy systems |
Option A: Use JSON for human-readable, easily debuggable message payloads Option B: Use binary formats (CBOR, Protocol Buffers) for compact, efficient encoding
Decision Factors:
| Factor | JSON | CBOR/Protobuf |
|---|---|---|
| Payload size | Large (50-100% overhead) | Small (10-30% of JSON) |
| Human readable | Yes (text-based) | No (requires decoder) |
| Debugging | Easy (curl, browser tools) | Requires specialized tools |
| Schema enforcement | Optional (JSON Schema) | Built-in (CDDL, .proto) |
| Parsing complexity | Moderate (string parsing) | Low (binary scanning) |
| CPU usage | Higher (text parsing) | Lower (direct decode) |
| Tooling ecosystem | Excellent (universal) | Good (growing) |
| Bandwidth cost | Higher | Lower |
Choose JSON when:
- Development and debugging convenience is priority (prototyping phase)
- Integrating with web services, REST APIs, or JavaScript clients
- Message frequency is low (hourly reports, configuration)
- Devices have sufficient processing power and bandwidth (Wi-Fi gateways)
- Team lacks binary protocol expertise
Choose Binary (CBOR/Protobuf) when:
- Bandwidth is constrained or metered (cellular, satellite, LPWAN)
- High message frequency makes overhead significant (10+ messages/second)
- Battery life depends on minimizing transmission time
- Strict schema validation is required for data quality
- Production systems where debugging tools are already in place
Default recommendation: JSON for development, cloud APIs, and low-frequency messages; CBOR for constrained devices and CoAP payloads; Protocol Buffers for high-volume systems with strong typing requirements
Example comparison (temperature reading):
// JSON: 42 bytes
{"device":"temp42","value":23.5,"unit":"C"}
// CBOR: ~20 bytes (binary, shown as hex)
A3 66 64 65 76 69 63 65 66 74 65 6D 70 34 32...
// Plain text: 4 bytes
23.5Design recommendations: - Battery sensors: Use CBOR or plain text (minimize bytes over air) - Cloud APIs: Use JSON (debugging, wide tool support) - High-frequency telemetry: Protocol Buffers (efficient, versioned) - Mixed systems: JSON at gateway, CBOR on constrained networks
1181.6 API Versioning Strategies
IoT systems run for years - versioning prevents breaking deployed devices:
Core Concept: API versioning provides a contract between API providers and consumers that allows the API to evolve without breaking existing clients.
Why It Matters: IoT devices deployed in the field may run for 5-10 years without firmware updates. Without versioning, any API change (adding required fields, changing response formats, deprecating endpoints) will break thousands of devices simultaneously, causing service outages and costly emergency patches.
Key Takeaway: Always version from day one using URI path versioning (/v1/) for IoT APIs - it is the simplest approach that works across all protocols and is immediately visible in logs and debugging tools.
1181.6.1 URI Versioning (Recommended for IoT)
# Version in path
coap://sensor.local/v1/temperature
coap://sensor.local/v2/temperature # New version with added metadata
# MQTT topic versioning
acme/v1/sensors/temp42/reading
acme/v2/sensors/temp42/reading
Pros: Simple, clear, works with any protocol Cons: Duplicate code if supporting multiple versions
1181.6.2 Header Versioning
GET /temperature
Accept: application/vnd.iot.v1+json
Pros: Clean URLs Cons: Embedded devices may not support custom headers
1181.6.3 Query Parameter
coap://sensor.local/temperature?version=1
Pros: Flexible, backward compatible Cons: Easy to forget, adds overhead
IoT-specific recommendation: Use URI versioning (/v1/, /v2/) because: - Simplest for embedded clients with limited HTTP stack - Clear in logs and debugging - No header parsing complexity - Works across all protocols (MQTT, CoAP, HTTP)
1181.7 Error Response Format
Consistent error handling reduces debugging time:
Standard error structure (JSON):
{
"error": {
"code": "SENSOR_OFFLINE",
"message": "Device has not reported in 5 minutes",
"timestamp": "2025-01-15T10:30:00Z",
"device_id": "sensor-42",
"retry_after": 300
}
}CoAP response codes:
2.01 Created - Resource created successfully
2.04 Changed - Resource updated
2.05 Content - Successful GET with payload
4.00 Bad Request - Invalid syntax
4.04 Not Found - Resource doesn't exist
5.00 Internal Server Error
MQTT error patterns:
# Publish errors to special topics
acme/errors/sensor-42 → {"code": "SENSOR_OFFLINE", ...}
# Or use QoS 0 for best-effort error reporting
1181.8 Rate Limiting and Throttling
Protect infrastructure from device misbehavior:
Core Concept: Rate limiting restricts the number of API requests a client can make within a specified time window, protecting servers from overload and ensuring fair resource allocation across clients.
Why It Matters: In IoT systems, a single malfunctioning device or firmware bug can generate thousands of requests per second, overwhelming your cloud infrastructure and causing cascading failures that affect all devices. Rate limiting acts as a circuit breaker that isolates misbehaving devices while keeping the system operational for well-behaved clients.
Key Takeaway: Implement rate limits at multiple levels (per-device, per-tenant, per-endpoint) and always return meaningful error responses (HTTP 429 with Retry-After header) so clients can implement proper backoff strategies rather than hammering your servers.
Patterns:
# Per-device limits
Device temp42: 1 request/second max
Response: 429 Too Many Requests (HTTP)
4.29 Too Many Requests (CoAP)
# Per-tenant limits
Organization ACME: 10,000 messages/minute
MQTT: Disconnect with reason code (0x97 Quota Exceeded)
Implementation: - Use token bucket algorithm (burst allowed, sustained rate limited) - Return Retry-After header with backoff time - Log violations for debugging misbehaving devices
1181.9 Security Best Practices
Always authenticate and authorize:
# CoAP with DTLS
coaps://sensor.local/v1/temperature # Note: 's' for secure
# MQTT with TLS + auth
Username: device-42
Password: [device-specific token]
Client Certificate: [for mutual TLS]
# HTTP Bearer tokens
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Design principles: - Never accept unauthenticated writes - Use TLS/DTLS even on local networks (prevents eavesdropping) - Rotate credentials regularly (especially for high-security deployments) - Rate-limit authentication attempts (prevent brute force)
1181.10 Case Study: Smart HVAC System API Design
Requirements: - 500 temperature sensors per building - Real-time alerts for anomalies - Historical data queries - Mobile app control
Solution - Hybrid approach:
# 1. MQTT for telemetry (sensors → cloud)
Topic: buildings/bldg1/floor3/zone-a/temp42/reading
Payload (CBOR): {t:23.5, h:45, ts:1642259400}
QoS: 0 (frequent updates, loss acceptable)
# 2. CoAP for control (app → actuators)
PUT coap://hvac.local/v1/zones/zone-a/setpoint
Payload: {"target":22.0}
Type: CON (confirmable - critical command)
# 3. HTTP REST for historical queries (app → cloud)
GET https://api.example.com/v1/sensors/temp42/history?start=2025-01-01
Response (JSON): [{"timestamp":"2025-01-01T00:00:00Z","value":23.5}...]
Why this works: - MQTT handles high-volume telemetry efficiently - CoAP provides low-latency local control - HTTP enables rich queries from mobile apps - Each protocol optimized for its use case
1181.11 Summary
This chapter covered practical REST API design patterns for IoT systems:
Key topics: - RESTful vs message-based patterns: Request-response for control, pub-sub for events - Topic and URI naming: Consistent hierarchies for MQTT topics and CoAP URIs - Payload format selection: JSON for debugging, CBOR/Protobuf for efficiency - API versioning: URI versioning recommended for simplicity and compatibility - Rate limiting and throttling: Token bucket algorithm, Retry-After headers - Security: TLS/DTLS, authentication on every request, credential rotation
1181.12 What’s Next?
Continue exploring REST API design:
- Worked Examples and Quizzes: Practice API design with thermostat and fleet management examples
- Real-time Protocols: VoIP, SIP, and RTP for audio/video IoT applications
For implementation details: - MQTT Fundamentals - CoAP Fundamentals and Architecture