Build a strongly-typed REST API in Express using TypeScript interfaces to process incoming sensor telemetry.
Domain
Backend Engineering / TS Types
Difficulty
⭐⭐⭐☆☆ (Intermediate)
Course Module
TypeScript for IoT
Deliverables
TS Router Files, Request validation Middlewares
1. Express Middleware Validation Lifecycle
Accepting raw payloads from remote devices without validating fields can lead to database corruption or server crashes. The diagram below details the Express middleware validation lifecycle. Incoming HTTP POST requests flow sequentially through logging and validation middlewares before reaching the route handlers. The schema validator verifies types (e.g. confirming `temperature` is a numeric float), rejecting malformed packets with a 400 Bad Request response.
2. Part 1: Step-by-Step Individual Code Implementation & Testing Steps
Follow these detailed steps to build the routing directory structure, write the schemas, configure validation middleware, and execute curl checks.
STEP 1
Launch VM Terminal and Create API Workspace
Boot up your VirtualBox Ubuntu machine. Open the terminal (Ctrl+Alt+T) and navigate to the project directory.
ubuntu@iot-vm:~$ cd ~/workspace/backend_scaffold && mkdir -p src/routes src/middlewares src/interfaces
We run `cd` and `mkdir` to generate a modular folder structure (`routes`, `middlewares`, `interfaces`) inside our backend workspace.
STEP 2
Create TypeScript Interface Specs File
Open a new file in gedit to write the TypeScript type definitions for the API.
We send a valid telemetry request to verify that the middleware passes the check and the route handler processes the data, returning a 201 Created response.
3. Router Endpoint Matrix Map
The table below lists the available API routes, including their HTTP methods, payload structures, validation requirements, and expected responses.
HTTP Method & Endpoint
Request Payload Schema
Validation Rules
Response Codes & Values
GET /api/devices
None
No body check
200 OK: Array of device profiles
POST /api/telemetry
{ deviceId, temperature, light }
deviceId (str), temp (float), light (int)
201 Created / 400 Bad Request
POST /api/commands
{ deviceId, command }
command must match "ON" or "OFF"
200 OK / 400 Bad Request
4. Part 2: Complete Codebases & Router Implementations
Below is the complete C++ firmware code showing how abstract inheritance interfaces work, followed by the complete Python script to listen to the serial port and print the data.
Screenshot of the terminal running curl validation checks, displaying the 400 Bad Request response for invalid data and the 201 Created response for valid payloads.
6. Closing Explanation: Why We Did This & What It Accomplishes
Architectural Intent & Operational Impact
Why We Did This
Defining TypeScript interfaces enforces type safety, reducing compilation bugs and ensuring that internal data handlers receive structured payloads.
Validating payloads in a dedicated middleware layer isolates the validation logic, keeping route handlers clean and focused on database operations.
Returning standard HTTP status codes (200, 201, 400) helps the client (ESP32 or Python client) handle errors gracefully, reducing network congestion.
What This Accomplishes
Builds a strongly-typed REST API in Express and TypeScript, complete with request validation and routing logic, providing a secure backend scaffold to handle incoming telemetry.