mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 22:32:04 +00:00
fix(openapi): declare what the measurement list and create answers carry
The sleep list rows of GET /api/measurements carry the main night's stage minutes, time in bed, time awake and awakenings, and the aggregate buckets carry the bucket's lowest and highest reading; none of these were in the contract. The create answer's union tried the plain row before the named sleep-stage result, so a contract check read a named-stage answer as a plain row and dropped its status. The responses are unchanged; the contract now says what they hold.
This commit is contained in:
1 parent
899b86f4d4
commit
f7051ee15f
2 files changed
+138
-2
No files matched your search
@@ -356,6 +356,36 @@ export const measurementResource = z
|
||||
.nonnegative()
|
||||
.optional()
|
||||
.describe("Time asleep across those naps, in minutes."),
|
||||
sleepStages: z
|
||||
.record(z.string(), z.number().nonnegative())
|
||||
.optional()
|
||||
.describe(
|
||||
"The main night's minutes per stage (`IN_BED`, `ASLEEP`, `AWAKE`, `CORE`, `DEEP`, `REM`), each the union of that stage's spans; empty on a day of naps alone.",
|
||||
),
|
||||
inBedMinutes: z
|
||||
.number()
|
||||
.nonnegative()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe(
|
||||
"The main night's time in bed in minutes, or null when no in-bed span was recorded.",
|
||||
),
|
||||
awakeMinutes: z
|
||||
.number()
|
||||
.nonnegative()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe(
|
||||
"The main night's time awake in bed in minutes, or null when no awake span was recorded.",
|
||||
),
|
||||
awakenings: z
|
||||
.number()
|
||||
.int()
|
||||
.nonnegative()
|
||||
.optional()
|
||||
.describe(
|
||||
"Awake spans between the main night's first and last time asleep.",
|
||||
),
|
||||
})
|
||||
.meta({
|
||||
id: "MeasurementResource",
|
||||
@@ -388,6 +418,20 @@ const aggregatedMeasurementBucket = z
|
||||
value: z.number().describe("The bucket's aggregated value."),
|
||||
measuredAt: isoDateTime().describe("Bucket start."),
|
||||
count: z.number().int().nonnegative().optional(),
|
||||
minValue: z
|
||||
.number()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe(
|
||||
"The lowest reading in the bucket; absent on a summed (cumulative) type.",
|
||||
),
|
||||
maxValue: z
|
||||
.number()
|
||||
.nullable()
|
||||
.optional()
|
||||
.describe(
|
||||
"The highest reading in the bucket; absent on a summed (cumulative) type.",
|
||||
),
|
||||
unit: z.string().optional(),
|
||||
})
|
||||
.meta({
|
||||
@@ -895,11 +939,15 @@ export const measurementPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
"Created. A single resource for the object body; an array of resources, in request order, for the array body; for a named sleep-stage body, the stored row with `status: inserted`.",
|
||||
content: {
|
||||
"application/json": {
|
||||
// The named-stage result first: it requires `status`, so a
|
||||
// plain row falls through to `measurementResource`, while a
|
||||
// union that tried the plain row first would read a named-stage
|
||||
// answer as a plain row and drop its `status`.
|
||||
schema: dataEnvelope(
|
||||
z.union([
|
||||
namedSleepStageResult,
|
||||
measurementResource,
|
||||
z.array(measurementResource),
|
||||
namedSleepStageResult,
|
||||
]),
|
||||
"CreateMeasurementResponse",
|
||||
),
|
||||
|
||||
Reference in new issue
Block a user