Logbook only returns the latest element - movesense

When trying to use Datalogger and Logbook I only get the latest reading when querying the device Logbook when I expect to get an array of the readings saved.
I'm trying to build a 1-Wire reading app to test the platform, I have defined a subscription API very similar to /Meas/Temp:
paths:
/OneWireTemp/Subscription:
post:
description: |
Subscribe to periodic temperature readings.
responses:
200:
description: Operation completed successfully
x-std-errors:
description: See common error codes http://developer.suunto.com/api/std-errors#subscribe
x-notification:
schema:
$ref: "#/definitions/TempMeasurement"
delete:
description: |
Unsubscribe to periodic temperature readings.
responses:
200:
description: Operation completed successfully
x-std-errors:
description: See common error codes http://developer.suunto.com/api/std-errors#unsubscribe
definitions:
TempMeasurement:
required:
- Timestamp
- Measurement
properties:
Timestamp:
description: Relative time of temperature reading
type: integer
format: uint32
x-unit: millisecond
Measurement:
description: Temperature reading
type: integer
format: int16
x-unit: celsius
I start the logging on device side with:
bool OneWireTempService::startDataLogger() {
WB_RES::DataEntry entry;
// Must match the subscription API path (without the /Subscription)
entry.path = "/OneWireTemp";
WB_RES::DataLoggerConfig dataLoggerConfig;
WB_RES::DataEntry entries[] = {entry};
dataLoggerConfig.dataEntries.dataEntry =
wb::MakeArray<WB_RES::DataEntry>(entries, 1);
wb::Result configureResult =
asyncPut(WB_RES::LOCAL::MEM_DATALOGGER_CONFIG(),
AsyncRequestOptions::Empty, dataLoggerConfig);
if (!wb::RETURN_OK(configureResult)) {
DebugLogger::error("Datalogger configuring failed: %u", configureResult);
return false;
}
wb::Result stateResult = asyncPut(
WB_RES::LOCAL::MEM_DATALOGGER_STATE(), AsyncRequestOptions::Empty,
WB_RES::DataLoggerStateValues::Type::DATALOGGER_LOGGING);
if (!wb::RETURN_OK(stateResult)) {
DebugLogger::error("Datalogger enabling failed: %u", stateResult);
return false;
}
return true;
}
and I update the subscription like this:
WB_RES::TempMeasurement tempMeasurement;
tempMeasurement.measurement = mTempReading;
tempMeasurement.timestamp = currentTime;
updateResource(WB_RES::LOCAL::ONEWIRETEMP(), ResponseOptions::Empty,
tempMeasurement);
Now on Android side I connect to the device using MDS library and MDS/Logbook/{Serial}/Entries returns a log after a while: {"elements": [{"Id": 2, "ModificationTimestamp": 1613406975, "Size": null}]}.
When querying MDS/Logbook/{Serial}/ById/2/Data now I only get the latest measurement: {"OneWireTemp":{"Measurement":2536,"Timestamp":2794239193}}. The reading is not even in an array.

This was fixed by wrapping the result in an array, then the Datalogger seemed to understand that there can be multiple entries in the log:
paths:
/OneWireTemp/Subscription:
post:
description: |
Subscribe to periodic temperature readings.
responses:
200:
description: Operation completed successfully
x-std-errors:
description: See common error codes http://developer.suunto.com/api/std-errors#subscribe
x-notification:
schema:
$ref: "#/definitions/OneWireTempMeasurements"
delete:
description: |
Unsubscribe to periodic temperature readings.
responses:
200:
description: Operation completed successfully
x-std-errors:
description: See common error codes http://developer.suunto.com/api/std-errors#unsubscribe
definitions:
OneWireTempMeasurements:
required:
- Measurements
properties:
Measurements:
description: Wrapper array
type: array
items:
$ref: '#/definitions/OneWireTempMeasurement'
OneWireTempMeasurement:
required:
- Timestamp
- Measurement
properties:
Timestamp:
description: Relative time of temperature reading
type: integer
format: uint32
x-unit: millisecond
Measurement:
description: Temperature reading in celsius
type: integer
format: int16
x-unit: celsius

Related

Shall I use oneOf or multiple attributes on the same object for a component of OpenAPI specification?

In short, here's fragment of OpenAPI specification:
# Consider an imaginary Internet Service Provider that needs to limit
# one or multiple customers in different ways: bandwidth (inbound, outbound), media type (text / music / video), volume (total traffic volume, for example, 5 GB).
# per specific website (a user can have different limit for YouTube and Amazon).
# You'll likely want to rename some of the attributes but
#that's not the point (this API is fake and that's the best example I came up with to reproduce the issue).
components:
schemas:
ProviderLimit:
type: object
properties:
name:
type: string
website_id:
type: string
users:
type: array
items:
type: string
description: List of user IDs
minItems: 1
bandwidth:
type: object
$ref: '#/components/schemas/BandwidthLimit'
volume:
type: object
$ref: '#/components/schemas/VolumeLimit'
media:
type: string
enum:
- TEXT
- MUSIC
- VIDEO
BandwidthLimit:
properties:
incoming_speed:
type: string
format: int64
outcoming_speed:
type: string
format: int64
VolumeLimit:
properties:
target:
type: string
format: int64
The question is which approach shall I take:
Merge all the possible limits (bandwith, volume, media), make them all optional, and agree to specify just one of them on the client.
Use oneOf.
# Example of using oneOf
components:
schemas:
ProviderLimit:
type: object
properties:
name:
type: string
website_id:
type: string
users:
type: array
items:
type: string
description: List of user IDs
minItems: 1
limit_type:
type: object
oneOf:
- $ref: '#/components/schemas/BandwidthLimit'
- $ref: '#/components/schemas/VolumeLimit'
- $ref: '#/components/schemas/MediaLimit'
discriminator:
propertyName: type # or something else
It looks like option #2 looks a little bit better but overall one could tell #1 option is somewhat reasonable (it's very simple and doesn't overcomplicate the API). Is there a strong argument to use #2 besides it just looks a little bit better (for example, there's a use case where using #1 might not lead to expected results)?

OpenAPI 3: How to require one or more properties in PATCH requestBody?

I have a User resource:
I want to define a PATCH /users/{uid} so that the client can update image, bio or both.
An example valid request body would be:
{
"image": "filename.jpg",
"bio": "My biography"
}
If the image property is sent alone the existing bio property will remain the same on the server and only the image will be updated. If both are sent (as above) both will change.
In short:
an empty request body {} is disallowed.
{"image": "new.jpg"}, {"bio": "new bio" or {"image": "new.jpg", "bio": "new bio" is allowed.
This is what I have so far. I'm using the anyOf object with two separate type: objects within. I've tried this with Swagger hub using the virtserver, but the virtual server always seems to return 200 OK and passes back the example data regardless of whatever is passed, so I have no way to know.
Does my definition do what I intended? If not, what the best practice?
openapi: 3.0.0
...
patch:
summary: update a user
parameters:
- in: path
name: uid
description: user id
schema:
type: string
required: true
requestBody:
description: Update a user's profile
content:
application/json:
schema:
type: object
anyOf:
- type: object
properties:
image:
type: string
- type: object
properties:
bio:
type: string
additionalProperties: false
required: true
responses:
'200':
description: Successfully updated
content:
application/json:
schema:
$ref: '#/components/schemas/User'
You can use minProperties: 1:
requestBody:
description: Update a user's profile
content:
application/json:
schema:
type: object
properties:
image:
type: string
bio:
type: string
minProperties: 1 # <-----------
additionalProperties: false
or anyOf + required:
type: object
properties:
image:
type: string
bio:
type: string
anyOf: # <-----------
- required: [image]
- required: [bio]
additionalProperties: false
Your original example defines an empty object {} because:
Without required or minProperties defined, all properties are optional.
More importantly, additionalProperties: false only knows about the properties defined directly alongside it and has no visibility into subschemas. So, in this example it disallows ALL properties.
As for:
I've tried this with SwaggerHub using the VirtServer, but the virtual server always seems to return 200 OK and passes back the example data regardless of whatever is passed.
This is because SwaggerHub mocks do not validate inputs and always return a static response based on the response schema.
From SwaggerHub documentation:
Note that the mock does not support business logic, that is, it cannot send specific responses based on the input.
...
The mock generates static responses for each API operation based on its responses and the response media types defined in the spec.
If an operation has multiple response codes, the mock returns the response with the lowest status code. For example, if an operation has responses 201, 202 and 400, the mock returns the 201 response.

How to describe list of particular objects using Swagger in Spring Boot?

I described my controller using Swagger but when I tried to extract .yaml description of controller, as response of endpoints I found list of objects. How to make Swagger describe those list as list of particular objects such as list of cars, list of houses, list of animals, etc. and then to describe what particular object like car, house or animal is.
My case is:
/dummy_endpoint:
get:
tags:
- foo-controller
summary: Get foo list
description: Send GET request to obtain foo list
operationId: findAllFooUsingGET
produces:
- application/json
responses:
'200':
description: Foo list obtained successfully
schema:
type: array
items:
type: object
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
What I want to get:
/dummy_endpoint:
get:
tags:
- foo-controller
summary: Get foo list
description: Send GET request to obtain foo list
operationId: findAllFooUsingGET
produces:
- application/json
responses:
'200':
description: Foo list obtained successfully
schema:
type: array
items:
type: Foo
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
definitions:
Foo:
type: object
properties:
id:
type: integer
format: int32
name:
type: String
I assume OpenAPI version 2.0 (based on the syntax in example). If you're using 3.0, let me know.
What you are looking for is ref. Check-in Swagger specification in section Input and Output Models and here in section Array and Multi-Value Parameters about arrays.
For example:
...
responses:
'200':
description: Foo list obtained successfully
schema:
type: array
items:
$ref: "#/definitions/Foo"
...
definitions:
Foo:
type: object
properties:
...
Thing that solved my problem was the usage of responseContainer property from #ResponseApi annotation, where I put type of response container like List, Array etc. and putting into response property type of objects that are stored into container.

Kaitai Struct - Optional block or attribute

My system has to be able to parse two types of very similar input data.
If the data comes from a queue it has the following structure:
record
record
...
record
If the data comes from a file it has the following structure:
header
record
record
...
record
My current code is as follows:
seq:
- id: file_header
type: file_header
- id: record
type: record
repeat: eos
types:
file_header:
seq:
- id: main_version
type: u1
- id: sub_version
type: u1
- id: spare
type: str
size: 30
encoding: UTF-8
record:
seq:
- id: event_id
type: u2
# enum: event_types
- id: event_length
type: u4
- id: enb_id
type: u4
- id: cell_id
type: u1
- id: call_id
type: u4
- id: date_time
type: date_time_record
- id: spare
type: str
size: 2
encoding: UTF-8
- id: crnti
type: u2
- id: body
size: event_length - 21
My idea is to create only one .ksy file that works for both approaches.
How can I get it?
It would basically be making file_header optional, but I don't see a way to do it.
Can somebody please help me on this?
Affiliate disclaimer: I'm a Kaitai Struct maintainer (see my GitHub profile).
My idea is to create only one .ksy file that works for both
approaches. How can I get it?
You can define a boolean parameter is_file on the top-level type and pass true when the data comes from a file, otherwise false. Like this:
params:
- id: is_file
type: bool
seq:
- id: file_header
type: file_header
if: is_file
- id: record
type: record
repeat: eos
types:
# ...
Note that the is_file param is mandatory, and you won't be able to instantiate the class without passing a value in it. For that reason, the fromFile(…​) helper method will no longer be available, and you'll need to create the parser object normally using new (or its closest equivalent in your target language).
I don't know what language you're targeting, but in C++, C#, Lua, PHP and Python come the custom params first (before _io, _root and _parent) and in Java, JavaScript and Nim second. For example, in Python you would do:
from kaitaistruct import KaitaiStream
from io import BytesIO
data = b"\x00\x01\x02..."
data_come_from_file = True
f = YourFormat(data_comes_from_file, KaitaiStream(BytesIO(data)))
In Java, for instance:
import io.kaitai.struct.ByteBufferKaitaiStream;
byte[] data = new byte[] { 0x00, 0x01, 0x02, ... };
boolean dataComeFromFile = true;
f = new YourFormat(new ByteBufferKaitaiStream(data), dataComesFromFile)
Check the generated code if unsure.

define common parameters for openapi/swagger annotations

On https://swagger.io/docs/specification/describing-parameters/ (OAS3) there is an example for common parameters which can be refered by $ref in paths and operations:
components:
parameters:
offsetParam: # <-- Arbitrary name for the definition that will be used to refer to it.
# Not necessarily the same as the parameter name.
in: query
name: offset
required: false
schema:
type: integer
minimum: 0
description: The number of items to skip before starting to collect the result set.
limitParam:
in: query
name: limit
required: false
schema:
type: integer
minimum: 1
maximum: 50
default: 20
description: The numbers of items to return.
paths:
/users:
get:
summary: Gets a list of users.
parameters:
- $ref: '#/components/parameters/offsetParam'
- $ref: '#/components/parameters/limitParam'
responses:
'200':
description: OK
/teams:
get:
summary: Gets a list of teams.
parameters:
- $ref: '#/components/parameters/offsetParam'
- $ref: '#/components/parameters/limitParam'
responses:
'200':
description: OK
How would I declare Swagger Annotations to produce this output, especially if the parameters are primitive type?
I tried
#Schema(type = "int")
#OpenAPIDefinition(info = #Info(description = "descr"))
public class OffsetParam {
public static final String DESCRIPTION =
"The number of items to skip before starting to collect the result set.";
#Parameter(description = "desc1")
public static OffsetParam valueOf(String value) {
return null;
}
}
but I only got
"components" : {
"schemas" : {
"OffsetParam" : {
"type" : "object"
},...
Do you have any idea which v3 annotations to add to a JAX-RS 2.1 resource?
My goal is to define those common parameters once and refer to them in all resources across my application.