Chapters

10 CoAP API Design: Resource and Response Contracts

coap
api

10.1 Start With the Decision

A field sensor can expose one value through several CoAP methods. The resource path, payload, and response code must form one clear contract.

10.2 Route Overview

This is part 1 of 2. Continue with CoAP API Design: Delivery and Security Decisions.

10.3 Part Objectives

  • Map sensor operations to CoAP resources and methods.
  • Select response codes and error payloads for common failures.

10.4 Chapter Roadmap

  • In 60 Seconds
  • Phoebe’s Field Notes: Does the 63% Number Survive Real Battery Physics?
  • Phoebe’s Field Notes: Separate Annual Charge from Pulse Survival
  • Start With the Sensor Menu
  • Quick Check: CoAP API Boundary
  • For Beginners: CoAP API Design
  • Building Sammy’s Data Menu
  • Prerequisites
  • Continue: CoAP Resource Contract and Negotiation Design
  • RESTful Resource Design
  • Minimum Viable Understanding: CoAP REST Design
  • Quick Check: Payload Format Selection
  • Error Handling
In 60 Seconds

Design the Sensor Menu Around One Decision

Picture a school room sensor that reports temperature every minute and accepts a new limit for its alarm. A useful interface must tell the operator what can be read, what can change, and what happens when a request arrives twice.

An application programming interface means a named way for programs to exchange requests and results; it is called an API. A protocol means shared rules for an exchange. Constrained Application Protocol (CoAP) means a compact request method for small devices. A payload means the useful data inside a message. JavaScript Object Notation (JSON) means a text format built from named values. A sampling rate means how often a sensor takes a reading. A gateway means the bridge between local devices and a wider network. Transport layer security means protection for a network exchange. Datagram Transport Layer Security (DTLS) applies it to separate messages.

Read the room value, change the alarm limit, repeat the same change, and send the wrong format. Then delay a reply and restart the gateway. Each result should state what changed, what did not, and who can try again.

This runway does not finish the interface or prove its security. The deeper material turns the menu into resource names, methods, formats, timing rules, and release tests. Designing CoAP APIs follows REST principles: structure resources as nouns (e.g., /sensors/temp/value), use CoAP methods as verbs (GET, POST, PUT, DELETE), and select compact content formats like CBOR over JSON to minimize payload size on constrained networks. Proper response codes (2.xx/4.xx/5.xx), DTLS security, and rate limiting are essential for robust production IoT APIs.

The mathematical gist. The chapter’s 525,600 yearly messages turn 0.278 µAh CON and 0.139 µAh NON charges into about 190 and 117 mAh/year after adding 43.8 mAh of background use. A 220 mAh cell therefore gives about 1.16 and 1.88 years, a 62.5% NON advantage. That charge result is independent of voltage, but the separate pulse check Vload=VocIRV_{load}=V_{oc}-IR gives 2.85 V for 10 mA through a fresh 15 ohm cell and only 2.00 V at 100 ohm.

Math Bridge · guided foundationsCan NON last longer and still brown out?Let Eddie keep annual charge and pulse voltage in two honest ledgers.

10.5 Start With the Sensor Menu

Before code, imagine what another device needs to ask: “what is the current value?”, “what format can I get?”, “may I change the sampling rate?”, and “how do I know the change worked?” A good CoAP API turns those questions into short resource paths, method rules, formats, response codes, and limits.

The story of this page is the move from a friendly idea to a resource contract that a sleepy client, gateway, cache, and security review can all understand.

10.6 Learning Objectives

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

  • Design RESTful CoAP APIs: Construct resource hierarchies using nouns with proper URI conventions and versioning strategies
  • Distinguish Content Formats: Compare JSON, CBOR, and text/plain payloads and select the appropriate format for constrained versus development environments
  • Implement Error Handling: Apply proper CoAP response codes (2.xx/4.xx/5.xx) and construct helpful error payloads for production systems
  • Configure Security Controls: Configure DTLS, rate limiting, and per-device access control for production CoAP deployments
  • Calculate Energy Tradeoffs: Calculate battery life impact of CON versus NON message types and justify the selection for different IoT use cases
  • Diagnose API Pitfalls: Identify and resolve common CoAP API problems such as Observe notification floods and proxy caching issues
Quick Check: CoAP API Boundary

Designing a CoAP API means deciding how IoT devices expose their data and accept commands. Think of it as creating a menu for your sensor — you define endpoints like /temperature or /status that other devices can read. Good API design makes your IoT system easy to use and understand, even for developers who have never seen your device before.

“I want other devices to read my temperature, but I also want them to set my sampling rate,” said Temperature Terry. “How do I organize all that?”

the microcontroller sketched out a plan. “You create a resource tree, Sammy! Your root is /sensor, and under it you have /sensor/temperature for reading data and /sensor/config for settings. When someone sends a GET to /sensor/temperature, they get your latest reading. When they send a PUT to /sensor/config, they can change your sampling rate.”

“Keep your URIs short!” advised the battery. “Every extra character in the path costs bytes, and CoAP packets should stay small enough to fit in a single UDP datagram. Use /temp instead of /temperature-reading-in-celsius. Every byte saved is energy saved!”

the LED added: “And don’t forget content negotiation! Some devices want your data in JSON, others in CBOR — which is like compressed JSON. Your API should let the requester choose the format using the Accept option. One sensor, multiple formats, everyone is happy!”

10.7 Prerequisites

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

10.8 Continue: CoAP Resource Contract and Negotiation Design

The main chapter below stays focused on the API design flow: resource naming, payload choices, security, rate limits, worked examples, and implementation checks. For the deeper contract behind URI/method/content-format/response-code tuples, Accept versus Content-Format negotiation, Max-Age and ETag cache behavior, Observe throttling, and HTTP-CoAP proxy mapping, continue to CoAP Resource Contract and Negotiation Design.

10.9 RESTful Resource Design

Minimum Viable Understanding: CoAP REST Design

Core Concept: CoAP follows REST principles - design resources as nouns, use HTTP-like methods as verbs. The URI identifies WHAT you’re accessing, the method specifies HOW.

Why It Matters: Consistent RESTful design makes APIs intuitive for developers, enables caching, supports proxying, and allows standard tooling to work seamlessly.

Key Takeaway: Good resource design: coap://sensor.local/v1/temperature (noun). Bad design: coap://sensor.local/getTemperature (verb in URL).

10.9.1 Good vs. Bad Resource Design

Good resource design (nouns):

Read these points as one connected sequence: start with coap://sensor.local/v1/temperature - read a temperature resource; then coap://sensor.local/v1/humidity - read a humidity resource; then coap://actuator.local/v1/led/state - manage LED state; and finish with coap://gateway.local/v1/config/network - update network settings.

  • coap://sensor.local/v1/temperature - read a temperature resource
  • coap://sensor.local/v1/humidity - read a humidity resource
  • coap://actuator.local/v1/led/state - manage LED state
  • coap://gateway.local/v1/config/network - update network settings

Poor resource design (verbs - avoid):

Read these points as one connected sequence: start with coap://sensor.local/getTemperature - verb in URL; and finish with coap://actuator.local/turnOnLED - action embedded in path.

  • coap://sensor.local/getTemperature - verb in URL
  • coap://actuator.local/turnOnLED - action embedded in path

REST operations on resources:

Read these points as one connected sequence: start with GET on .../v1/temperature reads the current value; then PUT on .../v1/led/state updates the LED state; then POST on .../v1/logs creates a new log entry; and finish with DELETE on .../v1/logs/2025-01 removes an old log bucket.

  • GET on .../v1/temperature reads the current value.
  • PUT on .../v1/led/state updates the LED state.
  • POST on .../v1/logs creates a new log entry.
  • DELETE on .../v1/logs/2025-01 removes an old log bucket.

10.9.2 URI Naming Conventions

CoAP URIs should be short (constrained bandwidth) but descriptive:

Recommended structure: host + version + resource type + device ID + subresource

Examples:

Read these points as one connected sequence: start with .../v1/devices/temp42/reading; then .../v1/devices/temp42/metadata; and finish with .../v1/devices/temp42/config.

  • .../v1/devices/temp42/reading
  • .../v1/devices/temp42/metadata
  • .../v1/devices/temp42/config

Best practices:

Read these points as one connected sequence: start with Version your API: use /v1/ so future changes do not break existing clients; then Use plural nouns: prefer /devices/temp42 over a singular collection name; then Keep it short: every character adds bytes on constrained links; then Lowercase with hyphens: /motion-sensors stays readable and URL-safe; and finish with Avoid deep nesting: stop around 3-4 levels; .../devices/sensors/temp/reading is too deep.

  • Version your API: use /v1/ so future changes do not break existing clients.
  • Use plural nouns: prefer /devices/temp42 over a singular collection name.
  • Keep it short: every character adds bytes on constrained links.
  • Lowercase with hyphens: /motion-sensors stays readable and URL-safe.
  • Avoid deep nesting: stop around 3-4 levels; .../devices/sensors/temp/reading is too deep.

10.9.3 Interactive URI Analysis

10.9.4 Payload Format Selection

Choose content format based on your constraints:

Read these points as one connected sequence: start with text/plain (0) - minimal bytes for a single value like "23.5"; then application/json (50) - easiest to inspect during development and debugging; then application/cbor (60) - smaller binary payload for production constrained devices; and finish with application/octet-stream (42) - raw binary only when both sides already share the schema.

  • text/plain (0) - minimal bytes for a single value like "23.5".
  • application/json (50) - easiest to inspect during development and debugging.
  • application/cbor (60) - smaller binary payload for production constrained devices.
  • application/octet-stream (42) - raw binary only when both sides already share the schema.

Example - Temperature reading in different formats:

Read these points as one connected sequence: start with Text/plain (4 bytes): 23.5; then JSON (42 bytes): device=temp42, value=23.5, unit=C; and finish with CBOR (~20 bytes): binary map carrying the same fields in a compact form.

  • Text/plain (4 bytes): 23.5
  • JSON (42 bytes): device=temp42, value=23.5, unit=C
  • CBOR (~20 bytes): binary map carrying the same fields in a compact form

Recommendation:

Read these points as one connected sequence: start with Battery sensors: Use text/plain or CBOR (minimize bytes); then Development: Use JSON (easy debugging); and finish with Production: Use CBOR (efficient, supports rich structures).

  • Battery sensors: Use text/plain or CBOR (minimize bytes)
  • Development: Use JSON (easy debugging)
  • Production: Use CBOR (efficient, supports rich structures)

10.9.5 Interactive Payload Comparison

Quick Check: Payload Format Selection

10.9.6 Versioning Strategy

IoT devices often run for years - plan for API evolution:

URI versioning (recommended for CoAP):

Read these points as one connected sequence: start with coap://sensor.local/v1/temperature - original API; and finish with coap://sensor.local/v2/temperature - new version with metadata.

  • coap://sensor.local/v1/temperature - original API
  • coap://sensor.local/v2/temperature - new version with metadata

Why URI versioning for IoT:

Read these points as one connected sequence: start with Simple for embedded clients; then No custom header parsing needed; then Clear in logs and debugging; and finish with Works with all CoAP libraries.

  • Simple for embedded clients
  • No custom header parsing needed
  • Clear in logs and debugging
  • Works with all CoAP libraries

Version migration example:

Read these points as one connected sequence: start with v1: GET coap://sensor.local/v1/temperature returns "23.5"; then v2: GET coap://sensor.local/v2/temperature returns a richer CBOR payload with value, unit, and timestamp; and finish with Rollout rule: legacy devices stay on v1 while new devices adopt v2.

  • v1: GET coap://sensor.local/v1/temperature returns "23.5".
  • v2: GET coap://sensor.local/v2/temperature returns a richer CBOR payload with value, unit, and timestamp.
  • Rollout rule: legacy devices stay on v1 while new devices adopt v2.

10.10 Error Handling

Use proper CoAP response codes and provide helpful error payloads:

10.10.1 Standard Response Codes

Read these points as one connected sequence: start with 2.01 Created - POST created a new resource; then 2.04 Changed - PUT updated an existing resource; then 2.05 Content - GET returned a payload; then 4.00 Bad Request - request syntax or payload was invalid; then 4.01 Unauthorized - authentication is required; then 4.04 Not Found - resource does not exist; then 4.05 Method Not Allowed - method does not apply to that resource; and finish with 5.00 Internal Server Error - server failed while handling the request.

  • 2.01 Created - POST created a new resource
  • 2.04 Changed - PUT updated an existing resource
  • 2.05 Content - GET returned a payload
  • 4.00 Bad Request - request syntax or payload was invalid
  • 4.01 Unauthorized - authentication is required
  • 4.04 Not Found - resource does not exist
  • 4.05 Method Not Allowed - method does not apply to that resource
  • 5.00 Internal Server Error - server failed while handling the request

10.10.2 Error Payload Format

JSON for human readability:

{
  "error": {
    "code": "SENSOR_OFFLINE",
    "message": "Device has not reported in 5 minutes",
    "timestamp": "2025-01-15T10:30:00Z",
    "device_id": "temp42",
    "retry_after": 300
  }
}

CBOR for production (more efficient):

  • 1 -> "SENSOR_OFFLINE"
  • 2 -> "Device offline"
  • 3 -> 1642259400
  • 4 -> "temp42"
  • 5 -> 300

10.11 Continue to the Next Part

Carry this evidence into CoAP API Design: Delivery and Security Decisions, which begins with Message Type Selection.