Start with the story: A REST API is the map a device, app, or service uses to talk about real things: thermostats, readings, commands, firmware, and alerts. Good design makes those things obvious in the URL, uses HTTP verbs consistently, and returns errors that tell the next engineer what actually happened.
In 60 Seconds
IoT REST API design requires choosing between RESTful and message-based patterns, designing consistent URI/topic naming, selecting compact payload formats (JSON vs CBOR vs Protocol Buffers), implementing API versioning, and applying rate limiting and TLS security suited to constrained devices.
Chapter Roadmap
This chapter works best if you read it as a design review checklist:
First decide which conversation pattern belongs where: REST or CoAP for commands and queries, MQTT for telemetry and event streams.
Then make the contract readable by naming resources, topics, versions, errors, and payload formats consistently.
Next use the JSON, CBOR, Protocol Buffers, versioning, and rate-limit calculators to test whether the design fits constrained devices and cloud cost limits.
After that connect security, the HVAC case study, and the REST explorer to deployment behavior rather than treating them as separate topics.
Finally use the quizzes and method-semantics deep dive to check retry safety, caching, and response contracts.
Checkpoint callouts summarize each major decision point. Existing interactives and quizzes are breathers: pause there, test the current rule, and then continue.
6.1 Learning Objectives
By the end of this chapter, you will be able to:
Distinguish RESTful vs Message-Based Patterns: Analyze the trade-offs between request-response (REST/CoAP) and publish-subscribe (MQTT) architectures to select the appropriate pattern for a given IoT use case
Design Topic and URI Naming Conventions: Construct consistent MQTT topic hierarchies and CoAP URI structures that scale to thousands of devices in multi-tenant deployments
Evaluate and Select Payload Formats: Compare JSON, CBOR, and Protocol Buffers across size, parsing overhead, and tooling constraints; justify format choices for constrained vs. cloud endpoints
Implement API Versioning Strategies: Apply URI path, header, and query-parameter versioning techniques; assess the cost of breaking changes against maintaining parallel API versions
Configure Rate Limiting and Throttling: Design token-bucket rate-limiting policies to protect infrastructure from device misbehavior and calculate the financial impact of unconstrained traffic
Apply IoT API Security Principles: Implement TLS/DTLS, per-request authentication tokens, and credential rotation; diagnose common authentication vulnerabilities in deployed IoT systems
Key Concepts
Core Concept: Fundamental principle underlying REST API Design Patterns — understanding this enables all downstream design decisions
Key Metric: Primary quantitative measure for evaluating REST API Design Patterns performance in real deployments
Trade-off: Central tension in REST API Design Patterns design — optimizing one parameter typically degrades another
Protocol/Algorithm: Standard approach or algorithm most commonly used in REST API Design Patterns implementations
Deployment Consideration: Practical factor that must be addressed when deploying REST API Design Patterns in production
Common Pattern: Recurring design pattern in REST API Design Patterns that solves the most frequent implementation challenges
Performance Benchmark: Reference values for REST API Design Patterns performance metrics that indicate healthy vs. problematic operation
6.2 For Beginners: REST API Patterns for IoT
REST API design patterns are proven templates for building interfaces that devices and applications use to communicate. Think of patterns as recipes – rather than inventing a new way to handle pagination, authentication, or error responses every time, you follow a well-tested approach that developers already know and expect.
Sensor Squad: Following the Recipe Book
“Every time I build an API, I start from scratch,” sighed Sammy the Sensor. “There must be a better way.”
Max the Microcontroller handed him a pattern book. “There is! Design patterns are like cooking recipes that smart engineers already figured out. For example, the pagination pattern: when you have 10,000 temperature readings, don’t dump them all at once. Send 50 at a time with a ‘next page’ link. It’s like reading a book chapter by chapter instead of swallowing the whole thing.”
“My favorite is the error response pattern,” said Lila the LED. “Instead of just saying ‘error’, you return a structured message with a code, a human-readable description, and a hint about what to fix. Like the difference between a teacher saying ‘wrong’ versus ‘wrong – try converting to Celsius first.’”
Bella the Battery added: “And the rate limiting pattern saves my energy. The API says ‘you can ask me 100 times per minute, but no more.’ This stops badly written apps from hammering a sensor with thousands of requests and draining its battery. Patterns protect both the client and the server!”
6.3 Prerequisites
Before diving into this chapter, you should be familiar with:
This chapter focuses on practical REST API design patterns for IoT systems.
6.5 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.
Understanding REST Constraints
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.
6.5.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!”).
6.5.2 Topic and URI Naming Conventions
Consistent naming prevents confusion in systems with thousands of devices:
6.5.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)
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)
6.6 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
Tradeoff: JSON vs Binary Payload Formats (CBOR/Protobuf)
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
Energy impact (LoRaWAN SF7/125 kHz, simplified proportional estimate):
Actual LoRaWAN airtime depends on spreading factor, coding rate, and header overhead using the Semtech formula — it is not simply linear in byte count. As a proportional approximation illustrating relative savings:
The example uses a minified UTF-8 JSON body, integer CBOR keys, and decimal gigabytes. The raw arithmetic is:
The JSON string {"device":"sensor-042","temp":23.5,"unit":"C","time":1705392000} is 64 bytes.
The CBOR estimate is 28 bytes, so the byte reduction is 64 - 28 = 36 bytes.
The percentage reduction is 36 / 64 = 0.5625, or 56.25% smaller.
Hourly reporting for 10,000 sensors gives 10,000 x 24 x 365 = 87,600,000 messages per year.
JSON traffic is 87,600,000 x 64 = 5,606,400,000 bytes, or 5.6064 GB using 1 GB = 1,000,000,000 bytes.
CBOR traffic is 87,600,000 x 28 = 2,452,800,000 bytes, or 2.4528 GB.
The annual saving is 5.6064 - 2.4528 = 3.1536 GB, which rounds to the 3.15 GB/year figure above.
For a real battery budget, combine this byte-count reduction with the radio’s airtime formula, retries, receive windows, wake cost, and sleep current. The 56% figure is a payload-size reduction; it only becomes an energy reduction when transmit airtime dominates the device budget.
Key insight: For battery-powered devices, every byte transmitted can shorten battery life. CBOR’s 56% payload reduction can approach a similar airtime saving for transmission-dominated budgets, but the measured power model decides the final battery result. The tradeoff: debugging requires binary decoders instead of simple text tools.
6.6.2 Interactive: Payload Format Size Comparison Calculator
Estimate serialized payload sizes for different formats based on the number and types of fields in your IoT message.
The payload section gives you the evidence a design review should keep:
You now know that the example JSON body is 64 bytes and the compact CBOR estimate is 28 bytes.
You now know that 64 - 28 = 36 bytes, or 56.25% smaller, is a payload-size claim first; it becomes an energy claim only when transmit airtime dominates the device budget.
You now know why the chapter recommends JSON for cloud APIs and debugging, CBOR for constrained CoAP payloads, and Protocol Buffers for high-volume systems with strong typing.
6.7 API Versioning Strategies
IoT systems run for years - versioning prevents breaking deployed devices:
Understanding API Versioning
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.
6.7.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
6.7.2 Header Versioning
GET /temperature
Accept: application/vnd.iot.v1+json
Pros: Clean URLs Cons: Embedded devices may not support custom headers
6.7.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)
Checkpoint: Naming the Contract
Before using the versioning calculator, verify that the API contract is readable without tribal knowledge:
You now know why REST should expose resources such as /devices/, /sensors/, and /readings/ rather than action URLs such as /getTemperature.
You now know why MQTT topics need organization, location, device type, device id, and data type fields when a deployment grows to thousands of devices.
You now know why URI versioning with /v1/ and /v2/ is the default IoT choice: it is visible in logs, works across protocols, and avoids custom header parsing on constrained clients.
6.7.4 Interactive: API Versioning Migration Cost Calculator
Compare the cost of breaking existing devices (modifying v1) versus maintaining parallel API versions.
{"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
6.9 Rate Limiting and Throttling
Protect infrastructure from device misbehavior:
Understanding Rate Limiting
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)
At this point the contract has names, formats, versions, errors, limits, and security boundaries:
You now know why a fleet with 50,000 deployed thermostats should add a /api/v2/ response rather than surprising strict v1 parsers with a new field.
You now know why 429 Too Many Requests, Retry-After, and a token bucket belong in the design, not only in incident response after a polling bug.
You now know why TLS, DTLS, per-request authentication, and credential rotation are part of the REST pattern: stateless APIs cannot rely on server-side sessions to remember trust.
6.11 Case Study: Smart HVAC System API Design
Case Study: Smart Building HVAC System
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
Interactive: REST API Explorer Animation
6.11.1 Choosing the Right Data Serialization Format: A Decision Framework
Payload format choice has outsized impact on constrained IoT devices. Here is a quantitative comparison for a typical sensor reading {"temperature": 23.5, "humidity": 45, "timestamp": 1706140800}:
Format
Encoded Size
Human Readable
Schema Required
Library Size (C)
Parse Speed
JSON
62 bytes
Yes
No
5-20 KB
Moderate
CBOR
35 bytes
No (binary)
No (self-describing)
2-5 KB
Fast
Protocol Buffers
18 bytes
No (binary)
Yes (.proto file)
30-100 KB
Very fast
MessagePack
38 bytes
No (binary)
No (self-describing)
3-8 KB
Fast
Custom binary
12 bytes
No
Yes (manual)
0 KB (hand-coded)
Fastest
If your project needs…
Choose…
Because…
Debugging ease, web dashboard integration
JSON
Universal tooling, browser-native, readable in logs
Compact payloads on constrained networks (LoRaWAN, 6LoWPAN)
CBOR
40-50% smaller than JSON, self-describing, IETF standard (RFC 8949)
Maximum efficiency with versioned schemas
Protocol Buffers
70%+ smaller than JSON, strong typing, backward-compatible evolution
Drop-in JSON replacement with size savings
MessagePack
JSON-compatible data model, ~40% smaller, minimal code changes
Extreme constraints (<1 KB payload budget)
Custom binary
Hand-pack fields at bit level, zero overhead, but no interoperability
Quick Decision Flowchart:
Is the payload going over LoRaWAN (51-242 byte limit)? Yes –> CBOR or custom binary
Do both ends share a compiled schema (.proto file)? Yes –> Protocol Buffers
Is the API consumed by web browsers or curl? Yes –> JSON (use CBOR for device-to-gateway, JSON for gateway-to-cloud)
Do you need a drop-in replacement for JSON with smaller size? Yes –> MessagePack
Default: CBOR for device-to-gateway communication; JSON for cloud APIs and dashboards
Worked Example: API Versioning Strategy for Deployed Thermostats
Scenario: A smart thermostat manufacturer has 50,000 devices deployed running firmware v1.2 connecting to /api/v1/thermostats. They need to add a new field humidity to the response without breaking existing devices.
Option A (modify v1): Emergency firmware push to 2,500 devices, support tickets, reputational damage = $125,000
Option B (v2 endpoint): Dev cost for v2 endpoint + maintain both APIs for 2 years = $45,000
Decision: Create v2 endpoint. Savings: $80,000 + zero downtime.
Common Mistake: Ignoring API Rate Limiting on IoT Devices
The Error: Not implementing rate limits on device APIs, assuming “our devices are well-behaved.” A firmware bug causes 1,000 devices to poll every 100ms instead of every 5 minutes.
Real Impact:
Normal traffic: 1,000 devices × 12 requests/hour = 12K req/hour
Bug traffic: 1,000 devices × 36,000 requests/hour = 36M req/hour (3,000× increase)
AWS API Gateway cost:
12K req/hour: $0.04/hour = $29/month (normal)
36M req/hour: $120/hour = $86,400/month (bug)
Damage: $86K bill + service outage for ALL devices (API throttled)
The Fix: Implement per-device rate limiting:
# Return 429 Too Many Requests after 20 requests/minute@app.route('/api/v1/temperature')@rate_limit(max_requests=20, window=60) # 20 per minute per devicedef get_temperature():return jsonify({"temp": 22.5})
Result: Bug triggers rate limit, affects only buggy devices. Bill capped at $150/month. Service continues for well-behaved devices.
Common Pitfalls
1. Prioritizing Theory Over Measurement in REST API Design Patterns
Relying on theoretical models without profiling actual behavior leads to designs that miss performance targets by 2-10×. Always measure the dominant bottleneck in your specific deployment environment — hardware variability, interference, and load patterns routinely differ from textbook assumptions.
2. Ignoring System-Level Trade-offs
Optimizing one parameter in isolation (latency, throughput, energy) without considering impact on others creates systems that excel on benchmarks but fail in production. Document the top three trade-offs before finalizing any design decision and verify with realistic workloads.
3. Skipping Failure Mode Analysis
Most field failures come from edge cases that work in the lab: intermittent connectivity, partial node failure, clock drift, and buffer overflow under peak load. Explicitly design and test failure handling before deployment — retrofitting error recovery after deployment costs 5-10× more than building it in.
Label the Diagram
Order the Steps
Match the Concepts
6.12 Deep Dive: Methods, Idempotency, and Conditional Caching
The patterns above cover URIs, versioning, and payloads. This layered walkthrough fills in the semantics that make a REST API survive a lossy IoT link: what each HTTP method promises, why idempotency decides whether a device can safely retry, and how ETag validators let a constrained device poll without re-downloading unchanged data.
REST models a system as resources named by URIs and acts on them with a small, agreed set of HTTP methods. A threshold should live under a noun such as /devices/42/config; the action belongs in PATCH or PUT, not in a custom endpoint like POST /setThreshold. Stable nouns make permissions, logs, test fixtures, and retry behavior easier to audit because each resource can list its allowed methods and expected outcomes once.
Shape
Example
Design use
Collection
/devices
List devices with GET; create with POST when the server assigns ids
Item
/devices/42
Read, replace, or delete one known device
Sub-resource
/devices/42/readings
Scope related data to its owner without inventing verbs
Anti-pattern
/setDeviceConfig
RPC-style URL hides method semantics from caches, proxies, and reviewers
Two method properties matter most on lossy IoT links. A method is safe when it makes no intended state change, so clients may cache, prefetch, or repeat it. A method is idempotent when doing it many times leaves the same state as doing it once. When a device times out after sending a request, it often cannot tell whether the server received it; idempotency decides whether the retry is harmless.
Method
Safe / idempotent
Typical IoT use
GET
Safe, idempotent
Read a sensor value or config; success is usually 200 OK
PUT
Not safe, idempotent
Replace a complete config resource; success is usually 200 OK or 204 No Content
PATCH
Not safe, not guaranteed idempotent
Partially update config; make patches idempotent when devices may retry
POST
Not safe, not idempotent
Create a resource or enqueue a command; use 201 Created or 202 Accepted
DELETE
Not safe, idempotent
Remove a rule or device; repeated deletes should not recreate state
A device that times out after PUT /devices/42/config can safely resend the same full representation, because two identical PUTs leave the same configuration. A blind retry of POST /commands can enqueue two commands. For retry-safe creation, either PUT to a client-chosen URI or send an idempotency key that the server deduplicates. Document that retry rule beside every method in the API contract.
Conditional requests solve the other expensive retry pattern: polling unchanged configuration. The server tags each representation with an ETag, such as ETag: "cfg-v7". The device stores that value and asks the server to send the body only if the representation changed:
GET /devices/42/config HTTP/1.1
Host: api.example
If-None-Match: "cfg-v7"
HTTP/1.1 304 Not Modified
ETag: "cfg-v7"
Cache-Control: max-age=30
sequenceDiagram
participant D as Device
participant S as Server
Note over D: Has stored ETag cfg-v7
D->>S: GET /config with If-None-Match cfg-v7
alt config unchanged
S-->>D: 304 Not Modified (no body)
else config changed
S-->>D: 200 OK, new body, new ETag
end
If nothing changed, 304 Not Modified confirms the device is current without transferring the body. If the config changed, the server returns 200 OK, the new body, and a new ETag. The same validator protects writes: If-Match: "cfg-v7" on a PUT tells the server to apply the update only if the resource is still at version 7; otherwise it returns 412 Precondition Failed and avoids overwriting another client’s change.
Cache-Control decides how intermediaries may reuse the response. max-age=60 lets a gateway reuse a device list for 60 seconds, no-cache allows storage but requires revalidation before use, and no-store is the safer choice for tokens and secrets. A release test should cover all three validator cases: unchanged reads return 304 without a body, changed reads return 200 with a new ETag, and stale writes fail with 412.
For each REST endpoint, document three retry facts beside the request example: whether the method is idempotent, whether clients need an idempotency key, and which validator or cache header proves the response can be reused.
Checkpoint: Retry and Cache Semantics
The deep dive turns REST naming into operational behavior:
You now know why repeated PUT can be safe for a full config replacement, while blind POST /commands retries can enqueue duplicate commands.
You now know how ETag, If-None-Match, 304 Not Modified, If-Match, and 412 Precondition Failed prevent wasted downloads and stale writes.
You now know what to document for every endpoint before release: idempotency, idempotency keys, validators, cache headers, and the status code a device should expect after a retry.
6.13 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