7  REST API Worked Examples

app-protocols
rest
api

Start with the story: The design rules become real when you have to choose the exact URL, method, status code, and payload for a smart thermostat or offline device. Each worked example turns an IoT situation into an API decision you can test.

In 60 Seconds

This chapter provides hands-on practice designing RESTful IoT APIs through worked examples covering resource hierarchies, proper HTTP status codes for device states, offline device handling, protocol selection between CoAP/MQTT/HTTP, and calculating protocol overhead impact on battery life.

Phoebe the physics guide

Phoebe’s Why

The 1000 mAh nameplate on the soil-moisture sensor’s battery is a charge rating, not an energy rating – it only becomes a usable energy budget once it is multiplied by the cell’s voltage, and that voltage is not the fixed number on the label. Every time the radio keys up, the cell’s own internal resistance drags the terminal voltage down below open-circuit, exactly during the burst that the mAh ledger is trying to account for. And the mAh figure itself is not fully spendable: some of it leaks away continuously as self-discharge whether or not the sensor ever transmits, and a derating margin has to stay in reserve so the electronics do not brown out before the label’s number is reached. The chapter’s own aside – “realistically a few years once self-discharge and temperature are included” – is the right instinct; the numbers below work out what “realistically” actually means.

The Derivation

Charge only becomes energy once voltage multiplies in:

\[E_{cell}\,(\mathrm{Wh}) = Q_{nameplate}\,(\mathrm{Ah})\times V_{oc}\]

A cell sags under load by its own internal resistance:

\[V_{term} = V_{oc} - I\,R_{int}\]

Usable charge is nameplate charge after a reserved cutoff/temperature margin \(\delta\):

\[Q_{usable} = Q_{nameplate}\times(1-\delta)\]

Self-discharge drains that same budget at a roughly constant rate even when the radio never keys up, so the realistic life divides usable charge by active consumption plus self-discharge together:

\[t_{realistic} = \frac{Q_{usable}}{\dot{Q}_{active} + \dot{Q}_{self\text{-}discharge}}\]

Worked Numbers: This Chapter’s Own Soil-Sensor Battery

Using the chapter’s own \(1000\) mAh cell and CoAP’s own \(0.86\) s/day of active time over 4 cycles: per-cycle active time \(= 0.86/4 = 0.215\) s, and the chapter’s own \(0.00267\) mAh per cycle implies an average active current \(I = (0.00267\times3600)/0.215 = 44.7\) mA.

  • Sag (catalog-typical Li-SOCl2 primary cell, \(V_{oc}=3.6\) V, \(R_{int}=15\ \Omega\), a chemistry chosen for its very low self-discharge on multi-year deployments): \(\Delta V = 0.0447\times15 = 0.671\) V, so \(V_{term} = 3.6-0.671 = 2.93\) V during every active burst – a real, repeatable dip the mAh ledger never shows.
  • Usable budget (30% reserved for cold-temperature capacity loss and cutoff-voltage headroom): \(Q_{usable} = 1000\times0.70 = 700\) mAh \(\to E_{usable} = 0.700\times3.6 = 2.52\) Wh
  • Self-discharge (catalog-typical \(1\%\)/year for Li-SOCl2): \(\approx 0.01\times1000 = 10.0\) mAh/yr, roughly constant against the near-full nameplate
  • Realistic life: CoAP’s own \(0.0347\) mAh/day \(=12.7\) mAh/yr \(+ 10.0 = 22.7\) mAh/yr \(\to 700/22.7 = 30.9\) yr. MQTT’s \(0.0438\) mAh/day \(=16.0\) mAh/yr \(+10.0=26.0\) mAh/yr \(\to 700/26.0=26.9\) yr. HTTP’s \(0.0445\) mAh/day \(\to 700/26.2=26.7\) yr.

All three protocols still clear the 2-year target by a wide margin, so the chapter’s protocol recommendation stands – but the idealised 27% CoAP-over-MQTT advantage (79 vs 62.5 yr) shrinks to about 15% (30.9 vs 26.9 yr) once self-discharge is added, because that 10.0 mAh/yr leak is the same fixed tax on every protocol. Self-discharge, not protocol overhead, is now the dominant term in the ledger.

Chapter Roadmap

This is a long worked-example chapter, so use it as a sequence of design decisions:

  1. First convert thermostat requirements into resource paths, methods, responses, and request load.
  2. Then handle an offline tracker without confusing stale data with missing resources.
  3. Next use the quizzes to test status codes, protocol choice, and byte-level overhead.
  4. After that use the calculators to scale requests, payloads, battery life, and fleet bandwidth.
  5. Finally read one HTTP exchange like a device contract and design the parking API yourself.

Checkpoints recap what each section has established, and the longer calculators can be treated as deep-dive tools on a first pass.

7.1 Learning Objectives

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

  • Design RESTful IoT APIs: Construct resource hierarchies that apply REST constraints to multi-device deployments
  • Implement Proper Error Handling: Select and apply the correct HTTP status codes for all device states including offline and missing resources
  • Diagnose Offline Device Scenarios: Distinguish between “no data” (404), “stale data” (200 with metadata), and “service unavailable” (503) in IoT REST APIs
  • Compare Protocol Trade-offs: Evaluate CoAP, MQTT, and HTTP against deployment constraints such as battery life, latency, and network topology
  • Calculate Protocol Overhead: Assess the byte-level impact of protocol choice on battery life and justify the selection for constrained IoT devices
  • Core Concept: Fundamental principle underlying REST API Practice — understanding this enables all downstream design decisions
  • Key Metric: Primary quantitative measure for evaluating REST API Practice performance in real deployments
  • Trade-off: Central tension in REST API Practice design — optimizing one parameter typically degrades another
  • Protocol/Algorithm: Standard approach or algorithm most commonly used in REST API Practice implementations
  • Deployment Consideration: Practical factor that must be addressed when deploying REST API Practice in production
  • Common Pattern: Recurring design pattern in REST API Practice that solves the most frequent implementation challenges
  • Performance Benchmark: Reference values for REST API Practice performance metrics that indicate healthy vs. problematic operation

7.2 For Beginners: REST API Examples

This chapter walks through complete REST API designs for real IoT scenarios. You will see how to create endpoints for reading sensor data, controlling actuators, and managing device fleets. Each example includes the URL structure, request format, and response format, so you can use them as templates for your own projects.

“Let’s build an actual API for our smart garden!” said Max the Microcontroller, rolling up his sleeves. “Sammy, you’re the temperature sensor at /api/v1/sensors/garden-temp. When someone sends a GET request to your URL, you reply with your current reading in JSON.”

Sammy practiced: “GET /api/v1/sensors/garden-temp and I respond with {\"value\": 24.5, \"unit\": \"celsius\", \"timestamp\": \"2026-02-07T10:30:00Z\"}. Easy!”

“Now for the sprinkler control,” Lila the LED continued. “POST to /api/v1/actuators/sprinkler/commands with a body like {\"action\": \"water\", \"duration_minutes\": 15}. The sprinkler turns on and returns a 202 Accepted status – meaning ‘got it, working on it’ – because watering takes time.”

Bella the Battery added the fleet management angle: “And GET /api/v1/devices?status=low-battery returns all devices that need charging. See how the URL pattern is consistent? Resources are nouns, actions use HTTP verbs, and filters go in query parameters. Follow the pattern and every developer who sees your API will instantly understand it!”

7.3 Prerequisites

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

7.4 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)
  4. Real-Time Protocol Workflows
  5. Protocol Selection Worked Examples

This chapter provides hands-on practice with REST API design through worked examples and comprehensive quizzes.


7.5 Worked Examples: REST API Design for IoT

These worked examples demonstrate practical REST API design decisions for real-world IoT scenarios.

The first example is deliberately concrete: one thermostat fleet, one mobile app, and a few endpoints that must stay predictable as the deployment grows.

Worked Example: Designing a Smart Thermostat REST API

Scenario: You are building a REST API for a smart thermostat system that allows mobile apps to read current temperature, set target temperature, and retrieve historical data. The system has 500 deployed thermostats.

Given:

  • Thermostat reports temperature every 30 seconds
  • Users want real-time display and control from mobile app
  • Historical data retention: 30 days
  • Expected concurrent mobile app users: 2,000

Steps:

  1. Define resource hierarchy - Organize resources around the device:

    /api/v1/thermostats/{device_id}              # Device info
    /api/v1/thermostats/{device_id}/temperature  # Current reading
    /api/v1/thermostats/{device_id}/setpoint     # Target temperature
    /api/v1/thermostats/{device_id}/history      # Historical readings
  2. Choose HTTP methods for each operation:

    • GET /thermostats/thermo-42/temperature - Read current temp (idempotent)
    • PUT /thermostats/thermo-42/setpoint - Set target (full update, idempotent)
    • GET /thermostats/thermo-42/history?start=2025-01-01&end=2025-01-15 - Query with filters
  3. Design response format with proper status codes:

    // GET /thermostats/thermo-42/temperature
    // Response: 200 OK
    {
      "device_id": "thermo-42",
      "current_temp_c": 22.5,
      "humidity_pct": 45,
      "timestamp": "2025-01-15T10:30:00Z",
      "unit": "celsius"
    }
    
    // PUT /thermostats/thermo-42/setpoint with body {"target_c": 21.0}
    // Response: 200 OK (or 204 No Content)
    {
      "device_id": "thermo-42",
      "target_c": 21.0,
      "estimated_time_minutes": 15
    }
    
    // GET /thermostats/nonexistent/temperature
    // Response: 404 Not Found
    {
      "error": "DEVICE_NOT_FOUND",
      "message": "Device 'nonexistent' is not registered",
      "timestamp": "2025-01-15T10:30:00Z"
    }

Result: A clean, RESTful API with predictable endpoints, proper HTTP semantics, and clear error handling. The hierarchy /thermostats/{id}/resource scales to thousands of devices while remaining intuitive for developers.

For a deployment of 500 thermostats reporting every 30 seconds, calculate the API request load:

\[\text{Requests per second} = \frac{500 \text{ devices}}{30 \text{ s}} \approx 16.67 \text{ req/s}\]

Each GET request (with HTTP/1.1 keep-alive) averages 250 bytes overhead + 120 bytes JSON payload = 370 bytes. Daily bandwidth:

\[\text{Daily data} = 16.67 \frac{\text{req}}{\text{s}} \times 370 \frac{\text{bytes}}{\text{req}} \times 86400 \frac{\text{s}}{\text{day}} = 533 \text{ MB/day}\]

For historical data queries returning 2,880 readings per thermostat per day (30-second intervals):

\[\text{Query payload} = 2880 \times 120 \text{ bytes} = 345 \text{ KB per device per day}\]

With 2,000 concurrent users, if 10% query historical data daily, that’s 200 users × 345 KB = 69 MB/day for historical queries. Total bandwidth: 533 + 69 = 602 MB/day, well within most cloud tier limits.

Key Insight: REST API design should follow the principle of resource-oriented design - model your API around nouns (thermostat, temperature, setpoint) not verbs (getTemperature, setTarget). The HTTP methods (GET, PUT, POST, DELETE) provide the verbs. This makes the API self-documenting and consistent across all resources.

Broker BexCheckpoint: Resource Modeling

You now know:

  • A 500-thermostat fleet reporting every 30 seconds produces about 16.67 requests per second.
  • Keeping resources as nouns lets GET, PUT, and query filters carry the action without inventing verb-style URLs.
  • The same hierarchy can return current readings, setpoints, history, and clean 404 Not Found errors without changing the API shape.

Worked Example: Handling Device Offline State in REST APIs

Scenario: A fleet management system has 1,000 GPS trackers on delivery trucks. Some trucks lose cellular connectivity in remote areas. Your REST API must handle requests for offline devices gracefully without confusing mobile app users.

Given:

  • GPS trackers report location every 60 seconds when connected
  • Some trucks go offline for hours in low-coverage areas
  • Mobile dispatch app needs last known location even when device is offline
  • App users must clearly understand device connectivity status

Steps:

  1. Define “offline” threshold and track last-seen timestamp:

    OFFLINE_THRESHOLD_SECONDS = 180  # 3 minutes without heartbeat
    
    def is_device_online(device_id):
        last_seen = get_last_heartbeat(device_id)
        age_seconds = (now() - last_seen).total_seconds()
        return age_seconds < OFFLINE_THRESHOLD_SECONDS
  2. Include connectivity metadata in every response:

    // GET /api/v1/vehicles/truck-42/location
    // Response: 200 OK (even if offline - we have cached data)
    {
      "vehicle_id": "truck-42",
      "latitude": 37.7749,
      "longitude": -122.4194,
      "speed_kmh": 0,
      "heading_degrees": 90,
      "timestamp": "2025-01-15T08:15:00Z",
      "connectivity": {
        "status": "offline",
        "last_seen": "2025-01-15T08:15:00Z",
        "offline_duration_minutes": 135
      }
    }
  3. Use appropriate HTTP status codes for different scenarios:

    @app.route('/api/v1/vehicles/<vehicle_id>/location')
    def get_location(vehicle_id):
        vehicle = db.get_vehicle(vehicle_id)
    
        if not vehicle:
            # Device never registered
            return {"error": "VEHICLE_NOT_FOUND"}, 404
    
        location = cache.get_last_location(vehicle_id)
    
        if not location:
            # Device registered but never reported location
            return {"error": "NO_LOCATION_DATA",
                    "message": "Device has not reported location yet"}, 404
    
        # Return cached location with connectivity status
        # Use 200 OK - we have valid data, just stale
        return {
            "vehicle_id": vehicle_id,
            "latitude": location.lat,
            "longitude": location.lng,
            "timestamp": location.timestamp.isoformat(),
            "connectivity": get_connectivity_status(vehicle_id)
        }, 200

Result: The API returns 200 OK with the last known location and explicit connectivity metadata, allowing the mobile app to display “Last seen 2 hours ago at [location]” rather than showing an error. The 404 status is reserved for truly missing resources (unknown vehicle ID).

Key Insight: For IoT REST APIs, distinguish between “no data” and “stale data”. A device being offline is not an error condition - it’s expected state information. Return cached/stale data with metadata about freshness rather than failing with 503 Service Unavailable. This keeps mobile apps functional even with intermittent device connectivity.

Broker BexCheckpoint: Offline Devices

You now know:

  • A tracker can be considered offline after 180 seconds without heartbeat, but that does not make the resource disappear.
  • 200 OK fits cached location plus connectivity metadata; 404 is for unknown vehicles or missing data.
  • 503 Service Unavailable is reserved for cases where the service cannot fulfill the request and should usually include retry guidance.
Quick Check: Offline Device Handling

The next few quizzes switch from reading examples to making choices. Treat each answer as a client-behavior contract: the status code tells firmware whether to retry, fix input, refresh credentials, or stop.

Code Challenge

7.6 Key Takeaways

Label the Diagram

Order the Steps

Match the Concepts

7.7 Summary

REST API Design Principles:

  • Model APIs around resources (nouns), not actions (verbs) – use HTTP methods (GET, PUT, POST, DELETE) as the verbs
  • Organize resource hierarchies: /api/v1/{collection}/{id}/{sub-resource} scales to thousands of devices
  • Include API versioning in the URL path (e.g., /api/v1/) for backward compatibility

Offline Device Handling:

  • Return 200 OK with stale data plus connectivity metadata for offline devices with cached data
  • Reserve 404 for truly missing resources (unknown device ID) and 503 for temporarily unavailable services
  • Include last_seen, offline_duration, and data_freshness fields so clients can make informed decisions

Protocol Selection for IoT:

  • CoAP over UDP: Best for battery-powered sensors with sporadic transmission (4-byte header, no TCP handshake)
  • MQTT over TCP: Best for publish-subscribe patterns with multiple subscribers (dashboards, cloud analytics)
  • Hybrid architectures (CoAP local + MQTT cloud) combine the strengths of both patterns

Common Pitfalls:

  • Returning 503 for offline devices when cached data is available (confuses mobile apps)
  • Using HTTP for battery-constrained sensors (92% protocol overhead for small payloads)
  • Designing verb-based endpoints (/getTemperature) instead of resource-based (/temperature)
Broker BexCheckpoint: Status and Protocol Choices

You now know:

  • 201 Created belongs to successful device registration, while 200 OK belongs to successful reads or cached stale data.
  • For a 4-byte payload over CoAP/UDP/IPv4/Ethernet, the chapter’s 46 header bytes make protocol overhead 92%.
  • CoAP fits constrained request-response sensors; MQTT fits publish-subscribe monitoring; HTTP is useful but expensive for tiny battery messages.

7.8 Knowledge Check: Matching and Sequencing

7.9 Quiz: Comprehensive Protocol Review

Quiz 2: Comprehensive Review

Scenario: Your IoT REST API receives a request for device data, but the device is offline. What HTTP status code should you return?

Situation Status Code Response Body Reasoning
Device never existed 404 Not Found {"error": "DEVICE_NOT_FOUND"} The resource ID is invalid
Device exists, never reported data 404 Not Found {"error": "NO_DATA_AVAILABLE"} The sub-resource (readings) doesn’t exist yet
Device offline, cached data available 200 OK Data + metadata We have valid (though stale) data to return
Device temporarily unreachable, no cache 503 Service Unavailable {"error": "DEVICE_UNAVAILABLE", "retry_after": 60} The service exists but can’t fulfill request now
Device permanently decommissioned 410 Gone {"error": "DEVICE_DECOMMISSIONED"} The resource existed but no longer does

Example response for offline device with cached data:

GET /api/v1/devices/sensor-042/temperature
Response: 200 OK
{
  "device_id": "sensor-042",
  "temperature_celsius": 22.5,
  "timestamp": "2026-02-07T14:30:00Z",
  "connectivity": {
    "status": "offline",
    "last_seen": "2026-02-07T14:30:00Z",
    "offline_duration_seconds": 3600,
    "data_freshness": "stale"
  }
}

Why 200 OK for stale data?

  • The API request was successful – we returned valid temperature data
  • The client can use the connectivity.status field to decide how to handle staleness
  • Mobile apps can display “Last updated 1 hour ago” without treating it as an error
  • Offline devices are expected in IoT – not an error condition

When to use 503 Service Unavailable:

  • Device is online but unresponsive (hung firmware)
  • No cached data available and request requires live data
  • Cloud gateway can’t reach device network (network partition)
  • Include Retry-After: 60 header to suggest retry timing

Key principle: IoT APIs should distinguish between “resource doesn’t exist” (404), “resource exists but unavailable” (503), and “resource available but data is stale” (200 with metadata).

7.10 Concept Relationships

Understanding how REST API design concepts interconnect:

  • Resource hierarchies determine endpoint structure, which directly impacts HTTP status code selection (404 vs 503 for missing resources)
  • Protocol overhead calculations (CoAP vs MQTT battery impact) inform protocol selection decisions for battery-powered deployments
  • Hybrid architectures (CoAP local + MQTT cloud) leverage strengths of both request-response and publish-subscribe patterns
  • Offline device handling requires distinguishing between no data (404) and stale data (200 with metadata), a pattern that extends to all IoT REST APIs

7.11 Interactive Calculators

The calculators turn the earlier examples into sliders. Use them after the quizzes to check whether an API shape still works when device count, report interval, payload size, or battery capacity changes.

7.11.1 REST API Request Load Calculator

Estimate the API request rate and daily bandwidth for your IoT device fleet.

7.11.2 Protocol Overhead Comparison Calculator

Compare the overhead percentage for CoAP, MQTT, and HTTP when sending small IoT payloads.

7.11.3 IoT Battery Life Estimator

Estimate battery life based on protocol choice, transmission frequency, and battery capacity.

7.11.4 REST API Response Size Estimator

Calculate the size of JSON API responses with device metadata and connectivity status fields.

7.11.5 Fleet Bandwidth Planner

Scale bandwidth estimates across fleet sizes and plan for growth.

Broker BexCheckpoint: Scaling the Numbers

You now know:

  • Request rate comes from device count divided by report interval, so growth can break an API before the endpoint design changes.
  • Payload and header bytes both matter; the thermostat example combined 250 bytes of HTTP overhead with 120 bytes of JSON payload.
  • Battery estimates depend on radio-on time as well as protocol headers, which is why a small byte saving may still matter in a sleep-heavy device.

7.12 Deep Dive: Reading an HTTP Message Like an Engineer

The worked examples above build whole endpoints. This layered walkthrough zooms into a single message on the wire: what the status-code classes promise, what each header in a request and response is doing, and how to choose the status code that tells a device exactly what to do next.

A REST response is a control signal for firmware, not just a message for a dashboard. The first digit of the status code sets the device action: 2xx means the request succeeded, 3xx means use a different or cached representation, 4xx means the client must change something, and 5xx means the server or upstream path failed. The exact code refines that action. For example, 202 Accepted fits a command queued for a sleeping device, while 204 No Content would falsely imply the action already completed.

Here is the device-registration exchange as a contract rather than a snippet:

POST /v1/devices HTTP/1.1
Host: api.example
Authorization: Bearer eyJhbGciOi...
Content-Type: application/json
Content-Length: 40

{"name":"gh2-temp","type":"temperature"}
HTTP/1.1 201 Created
Location: /v1/devices/42
Content-Type: application/json
Content-Length: 48

{"id":42,"name":"gh2-temp","type":"temperature"}

Authorization proves who is calling before anything is created. Content-Type tells the server and client how to parse the body. Content-Length must match the actual byte count so parsers can detect truncation or smuggling mistakes. Location is the authoritative URL for the new resource; the device should persist /v1/devices/42 instead of guessing its assigned identifier.

Symptom Right status Device action
Malformed JSON body 400 Bad Request Fix the payload; do not retry unchanged
Missing or expired token 401 Unauthorized Refresh credentials, then retry
Token lacks scope 403 Forbidden Stop or request authorization; retrying as-is will not help
Unknown device id 404 Not Found Correct the resource path or provisioning record
Over rate limit 429 Too Many Requests Back off and honor Retry-After
Gateway/server overloaded 503 Service Unavailable Retry later with backoff and honor Retry-After

flowchart TD
  A["Request failed"] --> B{"Client or server fault?"}
  B -->|Client| C{"Which client problem?"}
  B -->|Server overloaded| S["503 + Retry-After<br/>back off, then retry"]
  C -->|Malformed body| E1["400 Bad Request"]
  C -->|Expired token| E2["401 Unauthorized"]
  C -->|Missing scope| E3["403 Forbidden"]
  C -->|Unknown resource| E4["404 Not Found"]
  C -->|Over rate limit| E5["429 Too Many Requests"]

The two fleet-scale traps are status masking and retry amplification. Returning 200 OK with an error buried in the body tells caches, proxies, client libraries, and dashboards that the request succeeded. Returning 500 for a bad client payload makes devices retry a request that can never succeed. For sleeping or overloaded infrastructure, 503 Service Unavailable plus Retry-After: 300 turns a thundering-herd retry loop into an orderly wait.

For each worked example, write the status code beside the expected firmware action: retry now, retry after delay, refresh credential, change payload, re-provision resource, or stop. That line is the API contract devices actually execute.

Broker BexCheckpoint: Message Contracts

You now know:

  • Authorization, Content-Type, Content-Length, and Location are part of the API contract, not decorative headers.
  • 400, 401, 403, 404, 429, and 503 each imply a different device action.
  • Returning 200 OK with a hidden error or 500 for bad input can amplify retries across a fleet.

7.13 See Also

REST API Foundations:

Protocol Selection:

Implementation:

7.14 Try It Yourself

Hands-On Exercise: Design a Smart Parking REST API

Scenario: Create a REST API for a city parking system with 1,000 parking spots across 10 parking lots. Each spot has a magnetic sensor reporting occupied/vacant status.

Requirements:

  • Mobile app needs real-time spot availability
  • City operators need daily/monthly occupancy reports
  • Parking enforcement needs to verify payment for specific spots
  • System must handle sensor offline gracefully

Tasks:

  1. Design the resource hierarchy (parking lots, spots, sensors, reports)
  2. Define HTTP endpoints with proper methods (GET, POST, PUT)
  3. Specify status codes for: spot found occupied, spot not found, sensor offline
  4. Calculate protocol overhead: Compare HTTP vs CoAP for 1,000 sensors reporting every 30 seconds
  5. Design offline device handling: What should GET /lots/3/spots/42/status return if sensor hasn’t reported in 2 hours?

Verification Questions:

  • How many endpoints did you define? (Hint: At least 6-8 for full CRUD operations)
  • Did you distinguish between “spot doesn’t exist” (404) and “sensor offline” (200 with stale data)?
  • What’s the daily bandwidth consumption difference between HTTP and CoAP for your design?

Sample Solution Sketch:

GET    /lots                          # List all parking lots
GET    /lots/{lotId}/spots            # List spots in lot
GET    /lots/{lotId}/spots/{spotId}   # Get specific spot status
PUT    /lots/{lotId}/spots/{spotId}   # Update spot (internal only)
GET    /reports/occupancy?date=...    # Occupancy reports

For offline sensors:
GET /lots/3/spots/42 → 200 OK
{
  "spot_id": 42,
  "status": "occupied",
  "last_updated": "2026-02-09T08:15:00Z",
  "sensor": {
    "status": "offline",
    "last_seen": "2026-02-09T08:15:00Z",
    "offline_duration_minutes": 120
  }
}

7.15 What’s Next?

  • REST API Design Patterns Focus: Versioning, payload formats, pagination, rate limiting Why read it: Apply the design principles from this chapter to build production-ready API contracts

  • Application Protocols Overview Focus: Side-by-side comparison of CoAP, MQTT, and HTTP Why read it: Deepen the protocol selection skills practised in the quizzes above

  • Protocol Selection Worked Examples Focus: Agricultural sensor network end-to-end case study Why read it: See a full deployment decision from sensor hardware to cloud using the same frameworks

  • Real-Time Protocol Workflows Focus: VoIP, SIP, RTP for audio/video IoT Why read it: Extend your protocol knowledge to streaming and real-time communication patterns

  • MQTT Fundamentals Focus: Broker architecture, QoS levels, topic design Why read it: Implement the MQTT cloud-reporting leg of the hybrid architectures covered here

  • CoAP Fundamentals and Architecture Focus: CON/NON messages, observe, block transfer Why read it: Implement the CoAP local-control leg and understand the confirmable message reliability model