This is what response body I am trying to represent
[
{
measured_at | time_bucket,
[value] | [latitude, longitude, altitude] | [running, walking]
}...
]
Above is a bit of a shorthand notation for an array of JSON objects that will all have: the measured_at
OR time_bucket
, and either value
OR latitide
,longitude
,altitude
OR runnning
,walking
The closest schema I have written to achieving this is:
measurementsGetDynamicResponse:
type: array
items:
type: object
allOf:
# Combine measured_at or time_bucket with one of the measurement data combinations
- oneOf:
- properties:
measured_at:
type: string
format: date-time
description: "Timestamp of the data point"
- properties:
time_bucket:
type: string
description: "The time bucket for calculating the aggregation"
- properties:
value:
type: integer
- properties:
latitude:
type: number
format: float
description: "Latitude in decimal degrees"
longitude:
type: number
format: float
description: "Longitude in decimal degrees"
altitude:
type: number
format: float
description: "Altitude in meters"
- properties:
running:
type: integer
description: "Number of running steps"
walking:
type: integer
description: "Number of walking steps"
However, this schema doesn't separate the measurement groups, instead combining them all into one group:
(Swagger Example)
[
{
"measured_at": "2025-04-01T19:53:13.291Z",
"value": 0,
"latitude": 0,
"longitude": 0,
"altitude": 0,
"running": 0,
"walking": 0
},
{
"time_bucket": "string",
"value": 0,
"latitude": 0,
"longitude": 0,
"altitude": 0,
"running": 0,
"walking": 0
}
]
I tried grouping the measurement groups in a - oneOf
field:
measurementsGetDynamicResponse:
type: array
items:
type: object
allOf:
# Combine measured_at or time_bucket with one of the measurement data combinations
- oneOf:
- properties:
measured_at:
type: string
format: date-time
description: "Timestamp of the data point"
- properties:
time_bucket:
type: string
description: "The time bucket for calculating the aggregation"
- oneOf:
- properties:
value:
type: integer
- properties:
latitude:
type: number
format: float
description: "Latitude in decimal degrees"
longitude:
type: number
format: float
description: "Longitude in decimal degrees"
altitude:
type: number
format: float
description: "Altitude in meters"
- properties:
running:
type: integer
description: "Number of running steps"
walking:
type: integer
description: "Number of walking steps"
But it kept the measurement group together but separated them from the timestamps
(Swagger Example)
[
{
"measured_at": "2025-04-01T19:57:32.452Z"
},
{
"time_bucket": "string"
},
{
"value": 0
},
{
"latitude": 0,
"longitude": 0,
"altitude": 0
},
{
"running": 0,
"walking": 0
}
]
Any advice on how I can get the schema I am looking for?
Assume you are using OAS 3.0.x, where JSON Schema Draft-04 is necessary
This ends up being a very verbose schema because you need to constrain additional properties from each oneOf subschema, but also use allOf to create all of the possible values you are seeking.
each of time_bucket
and measured_at
must be defined for each oneOf option, then we use oneOf>required
to only allow one of those values.
Then each set of properties associated to the measurement types are defined with an empty schema because this allows you to use additionalProperties: false
as a sibling to allOf
.
$schema: http://json-schema.org/draft-04/schema#
type: object
properties:
measurementsGetDynamicResponse:
type: array
items:
oneOf:
- $ref: '#/definitions/measurement_and_value'
- $ref: '#/definitions/measurement_and_workouts'
- $ref: '#/definitions/measurement_and_geography'
definitions:
geographyType:
type: object
properties:
latitude:
type: number
format: float
description: Latitude in decimal degrees
longitude:
type: number
format: float
description: Longitude in decimal degrees
altitude:
type: number
format: float
description: Altitude in meters
workoutType:
type: object
properties:
running:
type: integer
description: Number of running steps
walking:
type: integer
description: Number of walking steps
valueType:
type: object
properties:
value:
type: integer
measurementType:
type: object
properties:
measured_at:
type: string
format: date-time
description: Timestamp of the data point
time_bucket:
type: string
description: The time bucket for calculating the aggregation
measurement_and_value:
additionalProperties: false
properties:
time_bucket: {}
measured_at: {}
value: {}
oneOf:
- required:
- measured_at
- required:
- time_bucket
allOf:
- $ref: "#/definitions/measurementType"
- $ref: "#/definitions/valueType"
measurement_and_workouts:
additionalProperties: false
properties:
time_bucket: {}
measured_at: {}
running: {}
walking: {}
oneOf:
- required:
- measured_at
- required:
- time_bucket
allOf:
- $ref: "#/definitions/measurementType"
- $ref: "#/definitions/workoutType"
measurement_and_geography:
additionalProperties: false
properties:
time_bucket: {}
measured_at: {}
longitude: {}
latitude: {}
altitude: {}
oneOf:
- required:
- measured_at
- required:
- time_bucket
allOf:
- $ref: "#/definitions/measurementType"
- $ref: "#/definitions/geographyType"
valid examples
{
"measurementsGetDynamicResponse": [
{
"time_bucket": "a time",
"running": 1,
"walking": 3
},
{
"measured_at": "2023-01-23",
"value": 1
},
{
"time_bucket": "test",
"longitude": 1.00
}
]
}