An HTTP API for sensor data
English translation
Learning objectives
A running server does not imply correct request handling. First test paths, missing inputs, and safe responses.
Execution conditions
Requires fastapi and httpx. Use uvicorn additionally only if you choose browser testing.
If the required package is missing, run %pip install fastapi==0.162.0 httpx==0.28.1 in a Colab or Jupyter code cell.
Test requests through function calls
Starting conditions
The FastAPI /readings path accepts device, start, and end. TestClient sends requests without starting an actual server.
Procedure
- Execute the provided valid request and check the status code and JSON fields.
- Execute a start>end request and distinguish it from a normal response.
Results to retain
- Response examples for valid and invalid requests.
from fastapi import FastAPI,HTTPException
from fastapi.testclient import TestClient
app=FastAPI()
readings=[{'device':'m1','time_s':0.,'value':20.},{'device':'m1','time_s':1.,'value':21.}]
@app.get('/readings')
def get_readings(device:str,start:float=0,end:float=10):
if start>end:raise HTTPException(status_code=400,detail='start must not exceed end')
return [row for row in readings if row['device']==device and start<=row['time_s']<=end]
client=TestClient(app)
for query in ['/readings?device=m1','/readings?device=m1&start=2&end=1']:
result=client.get(query);print(result.status_code,result.json())
Record results and self-check
Request:
Status code:
Key JSON fields:
Points to check
- Did you distinguish the roles of HTML pages and JSON APIs?
- Did you check the request flow without exposing the server externally?
Distinguish invalid requests
Starting conditions
Test a missing device, start=abc, nonexistent device m9, and nonexistent path /unknown.
Procedure
- Tabulate the status codes and response bodies for the four requests.
- Decide which situation to handle as an empty list: absent data or an invalid request.
- Use asserts to fix two valid and invalid request cases for checking after later changes.
Results to retain
- A table for 4 request types and a small regression test.
for path in ['/readings','/readings?device=m1&start=abc','/readings?device=m9','/unknown']:
response=client.get(path);print(path,response.status_code,response.json())
# TODO: Add assert checks for valid and invalid requests.
Record results and self-check
Request:
Status code:
Meaning:
Client's next action:
Points to check
- Did you distinguish 422 input validation from 404 path errors?
- Is the error body free of sensitive server internals?
The storage integration boundary
Starting conditions
You want to call the SQLite query function from the previous unit inside the API.
Procedure
- Mark where to replace reading from a temporary list with a storage function call.
- Separate API input validation from DB query responsibilities.
- Check whether one response identifies the device, time, and unit clearly enough for a user to interpret it.
Results to retain
- API–storage integration code or a function contract table.
# TODO: Modify the code to call query(device,start,end) from the previous unit.
# Run uvicorn locally only when testing in a browser.
Record results and self-check
Components:
Received input:
Return value:
Failure handling:
Points to check
- Did you avoid copying the query logic into each path?
- Can you reproduce the same request with TestClient before connecting external devices?