Chapters

9 REST APIs: Payload and Resource Design

app-protocols
rest
api
patterns

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.

9.1 Start With the Decision

A small sensor can spend more energy on JSON bytes than on its reading. Resource names and payload format must match the fleet constraint.

9.2 Route Overview

This is part 1 of 2. Continue with REST APIs: Versioning and Fleet Operations.

9.3 Part Objectives

  • Apply REST constraints to IoT resources and methods.
  • Calculate JSON and CBOR payload savings.
In 60 Seconds

An API is a set of rules that lets software ask another service for data or work. A protocol is the shared rule set used for an exchange. A payload is the useful data in a message. JSON is a text form used to name and carry data fields. TLS is a set of security rules that protects data as it crosses a network.

Imagine a heating service used by thousands of rooms. A device reads the current setting, sends a new setting, and reports a fault. Each action needs a clear name, allowed caller, reply, and retry rule.

Start with one device job. Define the resource, action, data fields, error reply, and version. Then send the same request twice, delay a reply, use an old version, exceed the request limit, and change data while a client holds an old copy. Record the result seen by both sides.

Use a repeat-safe action where the same request must not create extra work. Keep cache and retry rules explicit. Calling an interface REST does not prove safe device behavior. A neat web address does not solve duplicate commands, access control, fleet bursts, or future change.

Go deeper in two steps. The Practitioner sections compare payloads, versions, error forms, and rate limits. Under the Hood explains method meaning, repeat-safe actions, and checks that prevent stale updates.

Start with a small resource card. Name the room, device, reading, setting, or fault that the service exposes. Give it one stable ID. State who may read it and who may change it. Add the age after which its state is no longer safe to use.

Give each action the right job. A read asks for state. A create adds a new item. A full change replaces the named state. A small change updates named fields. A delete removes or ends the item. Do not use one action word for every case.

Make repeat behavior clear. A client may retry after a lost reply. The service must know whether the same request may run twice. Use a request ID for work that must happen once. Keep the first result so a safe retry can return it.

Name every field. Add its type, unit, range, need, and default. Keep time, source, and quality when they matter. Reject a wrong field instead of guessing. A compact payload is useful only when both sides share the same meaning.

Use one error shape. Include a short code, plain message, field clue, request ID, and safe next step. Keep secret detail out of public replies. Put full detail in the protected service log with the same request ID.

Plan for fleet bursts. Set a fair request limit for each device or user. Return the wait time when work must slow. Let urgent safety work use a distinct, proven path. A rate limit should protect the service without trapping devices in a fast retry loop.

Make cache age clear. A client may reuse a copy only while the service says it is fresh. Use a version mark when two writers could clash. Reject a change based on an old copy and tell the client to read again.

Keep change safe over years. Put the version in a stable place. Support old field units for a stated time. Test one old and one new client against the change. Record how an old version is warned, watched, and retired.

Protect the full path. Check the caller, allowed action, data, and device owner. Use TLS on the network. Keep keys out of code and logs. Limit each caller to the devices and actions it needs. Test a wrong user, old key, changed message, and repeated command.

End with a contract test. Send good, bad, late, repeated, old-version, too-fast, and stale requests. Keep the exact reply and final device state. A release is ready when another team can run the same set and reach the same result. 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
  • In 60 Seconds
  • Key Concepts
  • For Beginners: REST API Patterns for IoT
  • Following the Recipe Book
  • Prerequisites
  • How This Chapter Fits
  • IoT API Design Best Practices
  • Understanding REST Constraints
  • Payload Format Selection
  • Tradeoff: JSON vs Binary Payload Formats (CBOR/Protobuf)
  • Putting Numbers to It: JSON vs CBOR Payload Savings
  • Checkpoint: Payload Evidence

9.4 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

Read these points as one connected sequence: start with Core Concept: Fundamental principle underlying REST API Design Patterns — understanding this enables all downstream design decisions; then Key Metric: Primary quantitative measure for evaluating REST API Design Patterns performance in real deployments; then Trade-off: Central tension in REST API Design Patterns design — optimizing one parameter typically degrades another; then Protocol/Algorithm: Standard approach or algorithm most commonly used in REST API Design Patterns implementations; then Deployment Consideration: Practical factor that must be addressed when deploying REST API Design Patterns in production; then Common Pattern: Recurring design pattern in REST API Design Patterns that solves the most frequent implementation challenges; and finish with Performance Benchmark: Reference values for REST API Design Patterns performance metrics that indicate healthy vs. problematic operation.

  • 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

9.5 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.

“Every time I build an API, I start from scratch,” sighed Temperature Terry. “There must be a better way.”

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 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.’”

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!”

9.6 Prerequisites

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

9.7 How This Chapter Fits

REST API Design Series Navigation:

Read these points as one connected sequence: start with Introduction and Why Lightweight Protocols Matter; then Protocol Overview and Comparison; then REST API Design for IoT (Index); then Design Patterns (this chapter); then REST API Practice; then Real-Time Protocol Workflows; and finish with Protocol Selection Worked Examples.

  1. Introduction and Why Lightweight Protocols Matter
  2. Protocol Overview and Comparison
  3. REST API Design for IoT (Index)
  4. Real-Time Protocol Workflows
  5. Protocol Selection Worked Examples

This chapter focuses on practical REST API design patterns for IoT systems.


9.8 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.

9.8.1 RESTful vs Message-Based Patterns

The choice between REST (HTTP/CoAP) and message-based (MQTT) architectures fundamentally shapes your API design:

AspectREST (HTTP/CoAP)Message-Based (MQTT)
PatternRequest-ResponsePublish-Subscribe
StateStatelessConnection-based
DiscoveryURI pathsTopic hierarchy
ScalabilityHorizontal (add servers)Vertical (broker capacity)
Best ForCRUD operations, device controlEvent streams, telemetry
Client ComplexitySimple (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!”).

9.8.2 Topic and URI Naming Conventions

Consistent naming prevents confusion in systems with thousands of devices:

9.8.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:

Read these points as one connected sequence: start with Use lowercase, hyphens for readability; then Start with organization/tenant for multi-tenant systems; then Include location hierarchy for geographical filtering; then End with data type (temperature, status, event, command); and finish with Avoid special characters (/, +, #, $ reserved).

  • 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)

9.8.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:

Read these points as one connected sequence: start with Always version your API (/v1/, /v2/) to allow migration; then Use plural resource names (/devices/, not /device/); then Keep URIs short (remember constrained bandwidth); and finish with Use query parameters sparingly (adds overhead).

  • 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)

9.9 Payload Format Selection

The right payload format balances human readability, efficiency, and tooling support:

FormatSizeHuman ReadableSchema ValidationBest For
JSONLarge (verbose)YesJSON SchemaDevelopment, debugging, web apps
CBORSmall (binary)NoCDDLConstrained devices, low bandwidth
Protocol BuffersSmall (binary)No.proto filesHigh volume, multiple languages
MessagePackMediumNoNoneMixed environments
Plain TextVariableYesNoneSimple 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:

FactorJSONCBOR/Protobuf
Payload sizeLarge (50-100% overhead)Small (10-30% of JSON)
Human readableYes (text-based)No (requires decoder)
DebuggingEasy (curl, browser tools)Requires specialized tools
Schema enforcementOptional (JSON Schema)Built-in (CDDL, .proto)
Parsing complexityModerate (string parsing)Low (binary scanning)
CPU usageHigher (text parsing)Lower (direct decode)
Tooling ecosystemExcellent (universal)Good (growing)
Bandwidth costHigherLower

Choose JSON when:

Read these points as one connected sequence: start with Development and debugging convenience is priority (prototyping phase); then Integrating with web services, REST APIs, or JavaScript clients; then Message frequency is low (hourly reports, configuration); then Devices have sufficient processing power and bandwidth (Wi-Fi gateways); and finish with Team lacks binary protocol expertise.

  • 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:

Read these points as one connected sequence: start with Bandwidth is constrained or metered (cellular, satellite, LPWAN); then High message frequency makes overhead significant (10+ messages/second); then Battery life depends on minimizing transmission time; then Strict schema validation is required for data quality; and finish with Production systems where debugging tools are already in place.

  • 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: 43 bytes
{"device":"temp42","value":23.5,"unit":"C"}

// CBOR: ~30 bytes (binary, shown as hex; string keys retained)
A3 66 64 65 76 69 63 65 66 74 65 6D 70 34 32...

// Plain text: 4 bytes
23.5

Design recommendations:

Read these points as one connected sequence: start with Battery sensors: Use CBOR or plain text (minimize bytes over air); then Cloud APIs: Use JSON (debugging, wide tool support); then High-frequency telemetry: Protocol Buffers (efficient, versioned); and finish with Mixed systems: JSON at gateway, CBOR on constrained networks.

  • 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

How much bandwidth and energy can binary formats save? Let’s quantify the difference between JSON and CBOR for a typical IoT sensor payload.

Example payload: Temperature reading with metadata.

JSON representation (human-readable):

{"device":"sensor-042","temp":23.5,"unit":"C","time":1705392000}

Size=64 bytes (including whitespace and delimiters)\text{Size} = 64\text{ bytes (including whitespace and delimiters)}

CBOR representation (binary, using integer map keys 1-4 instead of string key names): Size28 bytes (compact binary encoding with integer keys)\text{Size} \approx 28\text{ bytes (compact binary encoding with integer keys)}

Bandwidth savings: Reduction=642864×100%=56% smaller payload\text{Reduction} = \frac{64 - 28}{64} \times 100\% = 56\%\text{ smaller payload}

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:

  • JSON (64 bytes): proportionally longer airtime at SF7 ≈ longer transmission
  • CBOR (28 bytes): 2864=44%\approx \frac{28}{64} = 44\% of JSON airtime
  • Transmission time savings: 642864×100%56% less airtime\frac{64 - 28}{64} \times 100\% \approx 56\%\text{ less airtime}

(For accurate airtime budgeting, use the Semtech LoRa Airtime Calculator with your specific SF, BW, and CR parameters.)

At scale (10,000 sensors, 1 message/hour for 1 year): Annual messages=10,000×24×365=87,600,000\text{Annual messages} = 10{,}000 \times 24 \times 365 = 87{,}600{,}000 JSON bandwidth=87,600,000×64=5.6 GB/year\text{JSON bandwidth} = 87{,}600{,}000 \times 64 = 5.6\text{ GB/year} CBOR bandwidth=87,600,000×28=2.45 GB/year\text{CBOR bandwidth} = 87{,}600{,}000 \times 28 = 2.45\text{ GB/year} Savings=3.15 GB/year (56% reduction)\text{Savings} = 3.15\text{ GB/year (56\% reduction)}

9.9.1 Calculation Audit

The example uses a minified UTF-8 JSON body, integer CBOR keys, and decimal gigabytes. The raw arithmetic is:

Read these points as one connected sequence: start with The JSON string {"device":"sensor-042","temp":23.5,"unit":"C","time":1705392000} is 64 bytes; then The CBOR estimate is 28 bytes, so the byte reduction is 64 - 28 = 36 bytes; then The percentage reduction is 36 / 64 = 0.5625, or 56.25% smaller; then Hourly reporting for 10,000 sensors gives 10,000 x 24 x 365 = 87,600,000 messages per year; then 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; then CBOR traffic is 87,600,000 x 28 = 2,452,800,000 bytes, or 2.4528 GB; and finish with The annual saving is 5.6064 - 2.4528 = 3.1536 GB, which rounds to the 3.15 GB/year figure above.

  • 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.

9.9.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.


Broker BexCheckpoint: Payload Evidence

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.

9.10 Continue to the Next Part

Carry this evidence into REST APIs: Versioning and Fleet Operations, which begins with API Versioning Strategies.