2  REST API Design

In 60 Seconds

RESTful IoT API design structures endpoints around resources (devices, sensors, readings) rather than actions, using standard HTTP methods (GET, POST, PUT, DELETE) with proper status codes and versioning. For production IoT, use compact payload formats like CBOR or Protocol Buffers instead of JSON to achieve 60-80% smaller messages, and always implement rate limiting and TLS to protect device infrastructure.

2.1 Learning Objectives

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

  • Design RESTful IoT APIs: Construct resource hierarchies applying REST constraints to devices, sensors, and readings
  • Implement Proper Error Handling: Configure HTTP status codes correctly to represent device states and failure modes
  • Select Payload Formats: Evaluate trade-offs between JSON, CBOR, and Protocol Buffers and justify the choice for a given deployment
  • Apply API Versioning: Implement URI, header, or query-parameter versioning strategies and distinguish their suitability for constrained devices
  • Calculate Rate Limiting Parameters: Analyze request load across device fleets and configure token-bucket algorithms to protect infrastructure
  • Assess IoT API Security: Diagnose authentication, authorization, and TLS configuration gaps in REST API designs

A REST API is a standardized way for devices and applications to communicate over the internet using simple requests like GET (read data) and POST (send data). Think of it as a restaurant menu – you look at what is available, place an order, and get a response. Most IoT cloud platforms use REST APIs for device management.

MVU: Minimum Viable Understanding

If you only have 5 minutes, here’s what you need to know about REST API design for IoT:

  1. Resources, not actions - Design around nouns (devices, sensors, readings) not verbs (getData, updateStatus)
  2. Use HTTP methods correctly - GET for reading, POST for creating, PUT for updating, DELETE for removing
  3. Choose compact formats - JSON for development, CBOR/Protobuf for production (60-80% smaller payloads)
  4. Version from day one - Use URI versioning (/api/v1/) - it’s simplest for embedded clients
  5. Rate limit everything - Device misbehavior can overwhelm servers; use token bucket algorithms

Bottom line: REST patterns translate well to IoT, but you must optimize for bandwidth, power, and unreliable connectivity. Design for offline-first, retry-with-backoff, and compact payloads.

Hey there, future IoT architect! Let’s learn about REST APIs with the Sensor Squad!

Sammy the Sensor wants to share his temperature readings with the world. But how does he talk to the cloud? He needs a common language that everyone understands - that’s where REST APIs come in!

Think of REST like a restaurant menu:

  • The menu (API) lists what you can order (resources)
  • GET is like asking “What’s today’s special?” (read data)
  • POST is like saying “I’ll have the soup!” (create new data)
  • PUT is like saying “Actually, change my order to salad” (update)
  • DELETE is like saying “Cancel my order” (remove)

The Sensor Squad Adventure:

  • Sammy sends his temperature to the cloud using POST /sensors/sammy/readings
  • Lila the Light Sensor checks her status with GET /sensors/lila/status
  • Max the Motion Detector updates his sensitivity with PUT /sensors/max/config
  • Bella the Button removes an old alert with DELETE /alerts/12345

Fun Analogy:

  • REST API is like a universal translator for devices
  • JSON is like writing a letter with lots of words
  • CBOR is like using emojis - smaller but means the same thing!

Why This Matters:

When your smart home talks to the cloud, REST APIs make sure everyone understands each other - whether it’s a tiny temperature sensor or a powerful video doorbell!

Try This: Next time you use a weather app, it’s probably using a REST API to GET the current temperature from sensors just like Sammy!

2.2 Prerequisites

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

2.3 How This Module Fits

Chapter Series Navigation:

  1. Introduction and Why Lightweight Protocols Matter
  2. Protocol Overview and Comparison
  3. REST API Design for IoT (this module)
  4. Real-time Protocols
  5. Worked Examples

This module focuses on practical REST API design patterns specifically for IoT systems, building on the protocol comparison from the previous chapter.


2.4 Module Overview

This module on REST API design for IoT has been organized into focused chapters for easier learning:

2.4.1 Chapter Guide

Chapter Topics Covered Estimated Time
Design Patterns RESTful patterns, naming conventions, payload formats, versioning, rate limiting, security 15-20 min
Worked Examples and Quizzes Thermostat API design, offline device handling, protocol overhead calculations, comprehensive quizzes 20-25 min

Total Module Time: ~35-45 minutes


2.5 Quick Reference

Chapter overview diagram showing two linked parts of the REST API Design module: design patterns and worked examples, with the main topic clusters under each.

REST API Design Module Overview

2.6 Key Concepts Summary

2.6.1 RESTful Design Principles

Resource-Oriented Design:

  • Model APIs around nouns (devices, sensors, readings), not verbs
  • HTTP methods provide the actions (GET, PUT, POST, DELETE)
  • Use consistent URI patterns: /api/v1/{resource}/{id}/{subresource}

Statelessness:

  • Each request contains all needed information
  • No server-side session state
  • Enables horizontal scaling and device reconnection

2.6.2 HTTP Methods and CRUD Operations

Diagram showing how HTTP methods map to CRUD operations for IoT resources: GET reads readings, POST creates new readings, PUT updates device configuration, and DELETE removes obsolete resources.

HTTP Methods Mapped to CRUD Operations in IoT

2.6.3 Interactive: API Request Rate Calculator

Calculate the request load on your API server based on device count and reporting frequency.

2.6.4 Payload Format Selection

Format Size Best For
JSON Large Development, debugging, web apps
CBOR Small Constrained devices, CoAP payloads
Protobuf Small High-volume, multi-language systems

2.6.5 Interactive: Payload Format Comparison

Compare payload sizes for different serialization formats to optimize bandwidth usage.

2.6.7 RESTful IoT Architecture

Architecture diagram showing IoT devices connecting through an API gateway with authentication, rate limiting, and load balancing to REST services, storage, and analytics in the cloud.

RESTful IoT Architecture Pattern

Common REST API Pitfalls in IoT

Avoid these common mistakes when designing REST APIs for IoT systems:

Pitfall Problem Solution
Verb-based URLs /api/getTemperature mixes actions into URLs Use nouns: /api/v1/sensors/{id}/readings
Missing pagination Returning all 10,000 sensor readings crashes mobile apps Add ?limit=100&offset=0 parameters
No rate limiting Single misbehaving device overwhelms server Token bucket: 100 req/min per device
Ignoring HTTP caching Same config fetched repeatedly wastes bandwidth Add ETag and Cache-Control headers
Verbose error messages “SQLException: table sensors column…” exposes internals Generic messages + internal logging
No versioning Breaking changes brick deployed devices Version from day one: /api/v1/

2.6.8 Interactive: Rate Limiting Token Bucket Simulator

Simulate token bucket algorithm to understand rate limiting behavior.

2.7 Start Learning

Recommended path:

  1. Start with Design Patterns - Learn RESTful patterns, naming conventions, payload formats, versioning, and security best practices

  2. Continue to Worked Examples - Practice with thermostat API design, offline device handling, and test your knowledge with comprehensive quizzes


Common Mistake: Not Implementing Exponential Backoff for Retries

The Mistake: An IoT cloud platform has 10,000 sensors reporting temperature data via REST API POST every 60 seconds. During a 5-minute server outage for emergency patching, all devices fail their POST requests. When the server comes back online, all 10,000 devices retry simultaneously at exactly 00:00, 01:00, 02:00, etc., because developers hardcoded a “retry every 60 seconds” strategy.

Why It Happens: Developers implement simple retry logic with fixed intervals because it’s easier to code than exponential backoff with jitter. The pattern while True: try_request(); sleep(60) seems reasonable until you multiply it by 10,000 concurrent devices.

What Actually Occurs (Thundering Herd):

14:35:00 - Server goes down for patching
14:35:01 - All 10,000 devices fail their POST, schedule retry at 14:36:01
14:36:01 - 10,000 simultaneous requests hit the server (just rebooted)
14:36:01 - Server overloaded: 8,500 requests time out (500 req/sec capacity)
14:36:01 - Failed devices schedule retry at 14:37:01
14:37:01 - 8,500 retries + 10,000 new scheduled posts = 18,500 simultaneous requests
14:37:01 - Server crashes again under load (cascading failure)

The Numbers:

  • Normal load: 10,000 devices ÷ 60 seconds = 167 requests/second (easily handled)
  • Thundering herd: 10,000 requests in 1 second = 60x spike (server overload)
  • Cascading failure: Each retry adds more synchronized devices, worsening the problem

The Fix: Implement exponential backoff with random jitter:

import random
import time

# ❌ BAD: Fixed retry interval
def post_with_fixed_retry(url, data):
    while True:
        response = requests.post(url, json=data)
        if response.status_code == 200:
            return response
        time.sleep(60)  # All devices retry at same time!

# ✅ GOOD: Exponential backoff with jitter
def post_with_backoff(url, data, max_retries=5):
    base_delay = 1  # Start with 1 second
    max_delay = 300  # Cap at 5 minutes

    for attempt in range(max_retries):
        try:
            response = requests.post(url, json=data, timeout=10)
            if response.status_code == 200:
                return response
            elif response.status_code == 429:  # Rate limited
                # Use Retry-After header if provided
                retry_after = int(response.headers.get('Retry-After', 0))
                if retry_after:
                    time.sleep(retry_after)
                    continue
        except requests.exceptions.RequestException:
            pass  # Network error, retry with backoff

        # Exponential backoff: 1s, 2s, 4s, 8s, 16s...
        delay = min(base_delay * (2 ** attempt), max_delay)

        # Add random jitter: +/- 50%
        jitter = delay * (0.5 + random.random())

        print(f"Retry {attempt+1}/{max_retries} after {jitter:.1f}s")
        time.sleep(jitter)

    raise Exception("Max retries exceeded")

# Example retry timing for 3 devices (same base, different jitter):
# Device A: 0.7s, 1.8s, 5.2s, 13.1s, 19.3s
# Device B: 1.2s, 2.4s, 3.8s, 10.9s, 24.7s
# Device C: 0.9s, 3.1s, 4.6s, 14.2s, 21.8s
# Result: Retries spread across 25-second window instead of synchronized

Retry Strategy Comparison:

Strategy First Retry Second Retry Spread Thundering Herd Risk
Fixed 60s 60s 60s 0% Extreme (all synchronized)
Exponential (no jitter) 1s 2s 0% High (powers of 2 collide)
Exponential + 50% jitter 0.5-1.5s 1-3s High Low (randomized)
Full jitter 0-2s 0-4s Maximum Minimal (uniform distribution)

Best Practice Configuration:

RETRY_CONFIG = {
    'base_delay': 1,      # 1 second minimum
    'max_delay': 300,     # 5 minutes maximum (prevent infinite growth)
    'max_retries': 5,     # Give up after 5 attempts
    'jitter_factor': 0.5, # +/- 50% randomization
}

# Total time before giving up: 1 + 2 + 4 + 8 + 16 = 31 seconds (with jitter: 15-46s)

Server-Side Support: Include Retry-After header in 503/429 responses:

# Flask example
@app.route('/api/v1/sensors/<sensor_id>/readings', methods=['POST'])
def post_reading(sensor_id):
    if server_overloaded():
        return jsonify({'error': 'Server overloaded'}), 503, {
            'Retry-After': '120'  # Tell clients to wait 2 minutes
        }

When to Use Different Strategies:

  • Fixed retry: Never in production IoT (only for testing)
  • Exponential backoff (no jitter): Acceptable for <100 devices
  • Exponential + jitter: Standard for 100-10,000 devices (use this by default)
  • Full jitter + server-directed backoff: Essential for 10,000+ devices

Thundering herd synchronization probability:

With 10,000 devices using fixed 60-second retry after a 5-minute outage, what’s the probability they all hit the same second?

Without jitter (all retry at exact 60-second intervals):

\[P(\text{synchronized}) = 1.0\]

All 10,000 devices retry at exactly 14:36:00, 14:37:00, etc.

With 50% jitter (retry between 30-90 seconds):

  • Retry window: 60 seconds
  • Devices spread uniformly across window
  • Expected devices per second: \(\frac{10000}{60} \approx 167\) devices/second

Load comparison:

  • No jitter: \(10000\text{ req/sec}\) (60× normal load of 167 req/sec)
  • With jitter: \(167\text{ req/sec}\) (same as steady-state!)

Retry timing variance with exponential backoff + jitter:

For attempt \(n\), delay \(d = \min(2^n \times \text{base}, \text{max}) \times (0.5 + U(0,1))\)

Where \(U(0,1)\) is uniform random in [0,1].

Spread across 10,000 devices (first retry, base=1s):

  • Mean delay: \(1 \times (0.5 + 0.5) = 1.0\) second
  • Standard deviation: \(1 \times \sigma_{U(0,1)} = 1 \times 0.289 = 0.289\) seconds
  • 10,000 devices spread over \(\approx 3\sigma = 0.87\) seconds (most devices)

This breaks synchronization completely—devices retry randomly within 0.5-1.5 second window.

Key Takeaway: Without exponential backoff and jitter, even a brief outage can trigger a cascading failure that keeps your system down far longer than the original issue. The “retry in 60 seconds” pattern seems fine for a single device but becomes a distributed denial-of-service attack against your own infrastructure when multiplied by thousands of devices. Always add randomization to break synchronization, and cap the maximum delay to prevent devices from disappearing for hours after a transient error.

2.7.1 Interactive: Exponential Backoff Visualizer

Visualize retry timing strategies to understand thundering herd prevention.

Common Pitfalls

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.

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.

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.

2.8 Concept Relationships

REST API design connects to:

Foundation Concepts:

Design Patterns:

Security:

  • API Security - Authentication, authorization, and rate limiting for IoT APIs
  • TLS for IoT - Securing REST endpoints with certificates

2.9 See Also

Implementation Guides:

Comparison Resources:

  • CoAP vs HTTP - When RESTful CoAP is better than HTTP for constrained devices
  • GraphQL for IoT - Alternative to REST for flexible data queries

Tools:

  • Postman - Testing REST APIs with collections
  • HTTPie - Command-line HTTP client for API testing
  • Swagger UI - Interactive API documentation

2.10 What’s Next?

Chapter Focus Why Read It
REST API Design Patterns Naming conventions, payload formats, versioning, security best practices Deepen practical skills for the patterns introduced in this overview module
REST API Worked Examples Thermostat API design, offline device handling, overhead calculations Apply concepts hands-on and test understanding with comprehensive quizzes
Real-time Protocols VoIP, SIP, and RTP for audio/video IoT Explore protocols that go beyond request-response for latency-sensitive streams
Protocol Selection Worked Examples Agricultural sensor network case study See REST vs MQTT vs CoAP trade-offs evaluated in a real end-to-end design
MQTT Fundamentals Publish-subscribe messaging, broker architecture, QoS levels Compare the message-based alternative to REST for event-driven IoT pipelines
CoAP Fundamentals and Architecture RESTful protocol for constrained nodes and lossy networks Implement REST-like semantics over UDP for the most resource-limited devices

2.11 Self-Assessment Checklist

Before moving on, ensure you can: