diff --git a/README.md b/README.md
index fce55097f9f..b6860841242 100644
--- a/README.md
+++ b/README.md
@@ -305,7 +305,7 @@ To learn more about the Nightscout API, visit https://YOUR-SITE.com/api-docs/ or
* `SHOW_PLUGINS` - enabled plugins that should have their visualizations shown, defaults to all enabled
* `SHOW_FORECAST` (`ar2`) - plugin forecasts that should be shown by default, supports space delimited values such as `"ar2 openaps"`
* `LANGUAGE` (`en`) - language of Nightscout. If not available english is used
- * Currently supported language codes are: bg (Български), cs (Čeština), de (Deutsch), dk (Dansk), el (Ελληνικά), en (English), es (Español), fi (Suomi), fr (Français), he (עברית), hr (Hrvatski), it (Italiano), ko (한국어), nb (Norsk (Bokmål)), nl (Nederlands), pl (Polski), pt (Português (Brasil)), ro (Română), ru (Русский), sk (Slovenčina), sv (Svenska), tr (Turkish), zh_cn (中文(简体)), zh_tw (中文(繁體))
+ * Currently supported language codes are: bg (Български), cs (Čeština), de (Deutsch), dk (Dansk), el (Ελληνικά), en (English), es (Español), fi (Suomi), fr (Français), he (עברית), hr (Hrvatski), hu (magyar), it (Italiano), ko (한국어), nb (Norsk (Bokmål)), nl (Nederlands), pl (Polski), pt (Português (Brasil)), ro (Română), ru (Русский), sk (Slovenčina), sv (Svenska), tr (Turkish), zh_cn (中文(简体)), zh_tw (中文(繁體))
* `SCALE_Y` (`log`) - The type of scaling used for the Y axis of the charts system wide.
* The default `log` (logarithmic) option will let you see more detail towards the lower range, while still showing the full CGM range.
* The `linear` option has equidistant tick marks; the range used is dynamic so that space at the top of chart isn't wasted.
diff --git a/app.js b/app.js
index c6528819bb9..2a94b1dd3e9 100644
--- a/app.js
+++ b/app.js
@@ -29,19 +29,7 @@ function create (env, ctx) {
const enableCSP = env.secureCsp ? true : false;
- console.info('Enabled SECURE_HSTS_HEADER (HTTP Strict Transport Security)');
- const helmet = require('helmet');
- var includeSubDomainsValue = env.secureHstsHeaderIncludeSubdomains;
- var preloadValue = env.secureHstsHeaderPreload;
- app.use(helmet({
- hsts: {
- maxAge: 31536000
- , includeSubDomains: includeSubDomainsValue
- , preload: preloadValue
- }
- , frameguard: false
- , contentSecurityPolicy: enableCSP
- }));
+ let cspPolicy = false;
if (enableCSP) {
var secureCspReportOnly = env.secureCspReportOnly;
@@ -60,7 +48,7 @@ function create (env, ctx) {
}
}
- app.use(helmet.contentSecurityPolicy({ //TODO make NS work without 'unsafe-inline'
+ cspPolicy = { //TODO make NS work without 'unsafe-inline'
directives: {
defaultSrc: ["'self'"]
, styleSrc: ["'self'", 'https://fonts.googleapis.com/', 'https://fonts.gstatic.com/', "'unsafe-inline'"]
@@ -76,7 +64,26 @@ function create (env, ctx) {
, frameAncestors: frameAncestors
}
, reportOnly: secureCspReportOnly
- }));
+ };
+ }
+
+
+ console.info('Enabled SECURE_HSTS_HEADER (HTTP Strict Transport Security)');
+ const helmet = require('helmet');
+ var includeSubDomainsValue = env.secureHstsHeaderIncludeSubdomains;
+ var preloadValue = env.secureHstsHeaderPreload;
+ app.use(helmet({
+ hsts: {
+ maxAge: 31536000
+ , includeSubDomains: includeSubDomainsValue
+ , preload: preloadValue
+ }
+ , frameguard: false
+ , contentSecurityPolicy: cspPolicy
+ }));
+
+ if (enableCSP) {
+
app.use(helmet.referrerPolicy({ policy: 'no-referrer' }));
app.use(bodyParser.json({ type: ['json', 'application/csp-report'] }));
app.post('/report-violation', (req, res) => {
@@ -276,9 +283,12 @@ function create (env, ctx) {
// API docs
const swaggerUi = require('swagger-ui-express');
+ const swaggerUseSchema = schema => (...args) => swaggerUi.setup(schema)(...args);
const swaggerDocument = require('./swagger.json');
+ const swaggerDocumentApiV3 = require('./lib/api3/swagger.json');
- app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
+ app.use('/api-docs', swaggerUi.serve, swaggerUseSchema(swaggerDocument));
+ app.use('/api3-docs', swaggerUi.serve, swaggerUseSchema(swaggerDocumentApiV3));
app.use('/swagger-ui-dist', (req, res) => {
res.redirect(307, '/api-docs');
diff --git a/docs/plugins/add-virtual-assistant-support-to-plugin.md b/docs/plugins/add-virtual-assistant-support-to-plugin.md
index 60ac1d1957b..6c581013b9e 100644
--- a/docs/plugins/add-virtual-assistant-support-to-plugin.md
+++ b/docs/plugins/add-virtual-assistant-support-to-plugin.md
@@ -36,9 +36,8 @@ There are 2 types of handlers that you can supply:
A plugin can expose multiple intent handlers (e.g. useful when it can supply multiple kinds of metrics). Each intent handler should be structured as follows:
+ `intent` - This is the intent this handler is built for. Right now, the templates used by both Alexa and Google Home use only the `"MetricNow"` intent (used for getting the present value of the requested metric)
-+ `metrics` - An array of metric name(s) the handler will supply. e.g. "What is my `metric`" - iob, bg, cob, etc. Make sure to add the metric name and its synonyms to the list of metrics used by the virtual assistant(s).
- - **IMPORTANT NOTE:** There is no protection against overlapping metric names, so PLEASE make sure your metric name is unique!
- - Note: Although this value *is* an array, you really should only supply one (unique) value, and then add aliases or synonyms to that value in the list of metrics for the virtual assistant. We keep this value as an array for backwards compatibility.
++ `metrics` - An array of metric name(s) the handler will supply. e.g. "What is my `metric`" - iob, bg, cob, etc. Although this value *is* an array, you really should only supply one (unique) value, and then add aliases or synonyms to that value in the list of metrics for the virtual assistant. We keep this value as an array for backwards compatibility.
+ - **IMPORTANT NOTE:** There is no protection against overlapping metric names, so PLEASE make sure your metric name is unique!
+ `intenthandler` - This is a callback function that receives 3 arguments:
- `callback` Call this at the end of your function. It requires 2 arguments:
- `title` - Title of the handler. This is the value that will be displayed on the Alexa card (for devices with a screen). The Google Home response doesn't currently display a card, so it doesn't use this value.
diff --git a/docs/plugins/alexa-templates/en-us.json b/docs/plugins/alexa-templates/en-us.json
index 79cc1baa977..20bf8c290d1 100644
--- a/docs/plugins/alexa-templates/en-us.json
+++ b/docs/plugins/alexa-templates/en-us.json
@@ -68,6 +68,14 @@
{
"name": "AMAZON.StopIntent",
"samples": []
+ },
+ {
+ "name": "AMAZON.CancelIntent",
+ "samples": []
+ },
+ {
+ "name": "AMAZON.HelpIntent",
+ "samples": []
}
],
"types": [
@@ -233,6 +241,16 @@
"name": {
"value": "cgm mode"
}
+ },
+ {
+ "name": {
+ "value": "db size",
+ "synonyms": [
+ "database size",
+ "data size",
+ "file size"
+ ]
+ }
}
]
}
diff --git a/docs/plugins/google-home-templates/en-us.zip b/docs/plugins/google-home-templates/en-us.zip
index d8ada2a834a..551e51307f0 100644
Binary files a/docs/plugins/google-home-templates/en-us.zip and b/docs/plugins/google-home-templates/en-us.zip differ
diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md
index 5b82bdfb053..fc76117059e 100644
--- a/docs/plugins/googlehome-plugin.md
+++ b/docs/plugins/googlehome-plugin.md
@@ -41,7 +41,8 @@ To add Google Home support for your Nightscout site, here's what you need to do:
1. Click on the "New Project" button.
1. If prompted, agree to the Terms of Service.
1. Give your project a name (e.g. "Nightscout") and then click "Create project".
-1. For the "development experience", select "Conversational" at the bottom of the list.
+1. When asked what kind of Action you want to build, select "Custom" and then click the "Next" button.
+1. When selecting how you want to build the project, scroll down to the bottom of the screen and click the link to build it using DialogFlow.
1. Click on the "Develop" tab at the top of the sreen.
1. Click on "Invocation" in the left navigation pane.
1. Set the display name (e.g. "Night Scout") of your Action and set your Google Assistant voice.
diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js
index 2a5fd4ef6cd..3c31bf1ce00 100644
--- a/lib/api/alexa/index.js
+++ b/lib/api/alexa/index.js
@@ -1,5 +1,6 @@
'use strict';
+var _ = require('lodash');
var moment = require('moment');
function configure (app, wares, ctx, env) {
@@ -18,7 +19,7 @@ function configure (app, wares, ctx, env) {
api.post('/alexa', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) {
console.log('Incoming request from Alexa');
- var locale = req.body.request.locale;
+ var locale = _.get(req, 'body.request.locale');
if(locale){
if(locale.length > 2) {
locale = locale.substr(0, 2);
@@ -78,19 +79,10 @@ function configure (app, wares, ctx, env) {
function handleIntent(intentName, slots, next) {
var metric;
if (slots) {
- if (slots.metric
- && slots.metric.resolutions
- && slots.metric.resolutions.resolutionsPerAuthority
- && slots.metric.resolutions.resolutionsPerAuthority.length
- && slots.metric.resolutions.resolutionsPerAuthority[0].status
- && slots.metric.resolutions.resolutionsPerAuthority[0].status.code
- && slots.metric.resolutions.resolutionsPerAuthority[0].status.code == "ER_SUCCESS_MATCH"
- && slots.metric.resolutions.resolutionsPerAuthority[0].values
- && slots.metric.resolutions.resolutionsPerAuthority[0].values.length
- && slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value
- && slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value.name
- ){
- metric = slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value.name;
+ var slotStatus = _.get(slots, 'metric.resolutions.resolutionsPerAuthority[0].status.code');
+ var slotName = _.get(slots, 'metric.resolutions.resolutionsPerAuthority[0].values[0].value.name');
+ if (slotStatus == "ER_SUCCESS_MATCH" && slotName) {
+ metric = slotName;
} else {
next(translate('virtAsstUnknownIntentTitle'), translate('virtAsstUnknownIntentText'));
return;
diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js
index b44715b25eb..cd42aa0ff37 100644
--- a/lib/api/googlehome/index.js
+++ b/lib/api/googlehome/index.js
@@ -1,5 +1,6 @@
'use strict';
+var _ = require('lodash');
var moment = require('moment');
function configure (app, wares, ctx, env) {
@@ -18,7 +19,7 @@ function configure (app, wares, ctx, env) {
api.post('/googlehome', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) {
console.log('Incoming request from Google Home');
- var locale = req.body.queryResult.languageCode;
+ var locale = _.get(req, 'body.queryResult.languageCode');
if(locale){
if(locale.length > 2) {
locale = locale.substr(0, 2);
diff --git a/lib/api/status.js b/lib/api/status.js
index b630d629593..56196114a07 100644
--- a/lib/api/status.js
+++ b/lib/api/status.js
@@ -32,6 +32,7 @@ function configure (app, wares, env, ctx) {
, settings: settings
, extendedSettings: extended
, authorized: ctx.authorization.authorize(authToken)
+ , runtimeState: ctx.runtimeState
};
var badge = 'http://img.shields.io/badge/Nightscout-OK-green';
diff --git a/lib/api3/doc/tutorial.md b/lib/api3/doc/tutorial.md
index 3d8c656dfbd..d69e95ef4a4 100644
--- a/lib/api3/doc/tutorial.md
+++ b/lib/api3/doc/tutorial.md
@@ -11,7 +11,7 @@ Each NS instance with API v3 contains self-included OpenAPI specification at [/a
---
### VERSION
-[VERSION](https://nsapiv3.herokuapp.com/api/v3/swagger-ui-dist/#/other/get_version) operation gets you basic information about software packages versions.
+[VERSION](https://nsapiv3.herokuapp.com/api3-docs/#/other/get_version) operation gets you basic information about software packages versions.
It is public (there is no need to add authorization parameters/headers).
Sample GET `/version` client code (to get actual versions):
@@ -38,7 +38,7 @@ Sample result:
---
### STATUS
-[STATUS](https://nsapiv3.herokuapp.com/api/v3/swagger-ui-dist/#/other/get_status) operation gets you basic information about software packages versions.
+[STATUS](https://nsapiv3.herokuapp.com/api3-docs/#/other/get_status) operation gets you basic information about software packages versions.
It is public (there is no need to add authorization parameters/headers).
Sample GET `/status` client code (to get my actual permissions):
@@ -75,7 +75,7 @@ Sample result:
---
### SEARCH
-[SEARCH](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/SEARCH) operation filters, sorts, paginates and projects documents from the collection.
+[SEARCH](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/SEARCH) operation filters, sorts, paginates and projects documents from the collection.
Sample GET `/entries` client code (to retrieve last 3 BG values):
```javascript
@@ -110,7 +110,7 @@ Sample result:
---
### CREATE
-[CREATE](https://nsapiv3.herokuapp.com/api/v3/swagger-ui-dist/#/generic/post__collection_) operation inserts a new document into the collection.
+[CREATE](https://nsapiv3.herokuapp.com/api3-docs/#/generic/post__collection_) operation inserts a new document into the collection.
Sample POST `/treatments` client code:
```javascript
@@ -140,7 +140,7 @@ Sample result:
---
### READ
-[READ](https://nsapiv3.herokuapp.com/api/v3/swagger-ui-dist/#/generic/get__collection___identifier_) operation retrieves you a single document from the collection by its identifier.
+[READ](https://nsapiv3.herokuapp.com/api3-docs/#/generic/get__collection___identifier_) operation retrieves you a single document from the collection by its identifier.
Sample GET `/treatments/{identifier}` client code:
```javascript
@@ -172,7 +172,7 @@ Sample result:
---
### LAST MODIFIED
-[LAST MODIFIED](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/other/LAST-MODIFIED) operation finds the date of last modification for each collection.
+[LAST MODIFIED](https://nsapiv3insecure.herokuapp.com/api3-docs/#/other/LAST-MODIFIED) operation finds the date of last modification for each collection.
Sample GET `/lastModified` client code (to get latest modification dates):
```javascript
@@ -199,7 +199,7 @@ Sample result:
---
### UPDATE
-[UPDATE](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/put__collection___identifier_) operation updates existing document in the collection.
+[UPDATE](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/put__collection___identifier_) operation updates existing document in the collection.
Sample PUT `/treatments/{identifier}` client code (to update `insulin` from 0.3 to 0.4):
```javascript
@@ -231,7 +231,7 @@ Sample result:
---
### PATCH
-[PATCH](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/patch__collection___identifier_) operation partially updates existing document in the collection.
+[PATCH](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/patch__collection___identifier_) operation partially updates existing document in the collection.
Sample PATCH `/treatments/{identifier}` client code (to update `insulin` from 0.4 to 0.5):
```javascript
@@ -259,7 +259,7 @@ Sample result:
---
### DELETE
-[DELETE](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/delete__collection___identifier_) operation deletes existing document from the collection.
+[DELETE](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/delete__collection___identifier_) operation deletes existing document from the collection.
Sample DELETE `/treatments/{identifier}` client code (to update `insulin` from 0.4 to 0.5):
```javascript
@@ -282,7 +282,7 @@ Sample result:
---
### HISTORY
-[HISTORY](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/HISTORY2) operation queries all changes since the timestamp.
+[HISTORY](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/HISTORY2) operation queries all changes since the timestamp.
Sample HISTORY `/treatments/history/{lastModified}` client code:
```javascript
@@ -326,4 +326,4 @@ Sample result:
}
]
```
-Notice the `"isValid":false` field marking the deletion of the document.
\ No newline at end of file
+Notice the `"isValid":false` field marking the deletion of the document.
diff --git a/lib/api3/index.js b/lib/api3/index.js
index 4bfe07a35fe..bff0899536f 100644
--- a/lib/api3/index.js
+++ b/lib/api3/index.js
@@ -7,7 +7,6 @@ const express = require('express')
, apiConst = require('./const.json')
, security = require('./security')
, genericSetup = require('./generic/setup')
- , swaggerSetup = require('./swagger')
;
function configure (env, ctx) {
@@ -35,7 +34,7 @@ function configure (env, ctx) {
self.setupApiEnvironment = function setupApiEnvironment () {
-
+
app.use(bodyParser.json({
limit: 1048576 * 50
}), function errorHandler (err, req, res, next) {
@@ -100,7 +99,10 @@ function configure (env, ctx) {
self.setupApiEnvironment();
genericSetup(ctx, env, app);
self.setupApiRoutes();
- swaggerSetup(app);
+
+ app.use('/swagger-ui-dist', (req, res) => {
+ res.redirect(307, '../../../api3-docs');
+ });
ctx.storageSocket = new StorageSocket(app, env, ctx);
diff --git a/lib/api3/swagger.js b/lib/api3/swagger.js
deleted file mode 100644
index ff965061c87..00000000000
--- a/lib/api3/swagger.js
+++ /dev/null
@@ -1,41 +0,0 @@
-'use strict';
-
-const express = require('express')
- , fs = require('fs')
- ;
-
-
-function setupSwaggerUI (app) {
-
- const serveSwaggerDef = function serveSwaggerDef (req, res) {
- res.sendFile(__dirname + '/swagger.yaml');
- };
- app.get('/swagger', serveSwaggerDef);
-
- const swaggerUiAssetPath = require('swagger-ui-dist').getAbsoluteFSPath();
- const swaggerFiles = express.static(swaggerUiAssetPath);
-
- const urlRegex = /url: "[^"]*",/;
-
- const patchIndex = function patchIndex (req, res) {
- const indexContent = fs.readFileSync(`${swaggerUiAssetPath}/index.html`)
- .toString()
- .replace(urlRegex, 'url: "../swagger.yaml",');
- res.send(indexContent);
- };
-
- app.get('/swagger-ui-dist', function getSwaggerRoot (req, res) {
- let targetUrl = req.originalUrl;
- if (!targetUrl.endsWith('/')) {
- targetUrl += '/';
- }
- targetUrl += 'index.html';
- res.redirect(targetUrl);
- });
- app.get('/swagger-ui-dist/index.html', patchIndex);
-
- app.use('/swagger-ui-dist', swaggerFiles);
-}
-
-
-module.exports = setupSwaggerUI;
\ No newline at end of file
diff --git a/lib/api3/swagger.json b/lib/api3/swagger.json
new file mode 100644
index 00000000000..b20bb0e6761
--- /dev/null
+++ b/lib/api3/swagger.json
@@ -0,0 +1,2251 @@
+{
+ "openapi": "3.0.0",
+ "info": {
+ "title": "Nightscout API",
+ "description": "Nightscout API v3 is a component of cgm-remote-monitor project. It aims to provide lightweight, secured and HTTP REST compliant interface for your T1D treatment data exchange.\n\nAPI v3 uses these environment variables, among other things:\n- Security switch (optional, default = `true`)
API3_SECURITY_ENABLE=true
You can turn the whole security mechanism off, e.g. for debugging or development purposes, but this should never be set to false in production.\n\n- Number of minutes of acceptable time skew between client's and server's clock (optional, default = 5)
API3_TIME_SKEW_TOLERANCE=5
This security parameter is used for preventing anti-replay attacks, specifically when checking the time from `Date` header.\n\n- Maximum limit count of documents retrieved from single query
API3_MAX_LIMIT=1000
\n\n- Autopruning of obsolete documents (optional, default is only `DEVICESTATUS`=60)
You can specify for which collections autopruning will be activated and length of retention period in days, e.g. \"Hold 60 days of devicestatus, automatically delete older documents, hold 365 days of treatments and entries, automatically delete older documents.\"\n\n- Fallback deduplication switch (optional, default = true)
API3_DEDUP_FALLBACK_ENABLED=true
API3 uses the `identifier` field for document identification and mutual distinction within a single collection. There is automatic deduplication implemented matching the equal `identifier` field. E.g. `CREATE` operation for document having the same `identifier` as another one existing in the database is automatically transformed into `UPDATE` operation of the document found in the database.\nDocuments not created via API v3 usually does not have any `identifier` field, but we would like to have some form of deduplication for them, too. This fallback deduplication is turned on by having set `API3_DEDUP_FALLBACK_ENABLED` to `true`. When searching the collection in database, the document is found to be a duplicate only when either he has equal `identifier` or he has no `identifier` and meets:
`devicestatus` collection: equal combination of `created_at` and `device`\n`entries` collection: equal combination of `date` and `type`\n`food` collection: equal `created_at`\n`profile` collection: equal `created_at`\n`treatments` collection: equal combination of `created_at` and `eventType`
\n\n- Fallback switch for adding `created_at` field along the `date` field (optional, default = true)
API3_CREATED_AT_FALLBACK_ENABLED=true
Standard APIv3 document model uses only `date` field for storing a timestamp of the event recorded by the document. But there is a fallback option to fill `created_at` field as well automatically on each insert/update, just to keep all older components working.",
+ "contact": {
+ "name": "NS development discussion channel",
+ "url": "https://gitter.im/nightscout/public"
+ },
+ "license": {
+ "name": "AGPL 3",
+ "url": "https://www.gnu.org/licenses/agpl.txt"
+ },
+ "version": "3.0.1"
+ },
+ "servers": [
+ {
+ "url": "/api/v3"
+ }
+ ],
+ "tags": [
+ {
+ "name": "generic",
+ "description": "Generic operations with each database collection (devicestatus, entries, food, profile, settings, treatments)"
+ },
+ {
+ "name": "other",
+ "description": "All other various operations"
+ }
+ ],
+ "paths": {
+ "/{collection}": {
+ "get": {
+ "tags": [
+ "generic"
+ ],
+ "summary": "SEARCH: Search documents from the collection",
+ "description": "General search operation through documents of one collection, matching the specified filtering criteria. You can apply:\n\n1) filtering - combining any number of filtering parameters\n\n2) ordering - using `sort` or `sort$desc` parameter\n\n3) paging - using `limit` and `skip` parameters\n\nWhen there is no document matching the filtering criteria, HTTP status 204 is returned with empty response content. Otherwise HTTP 200 code is returned with JSON array of matching documents as a response content.\n\nThis operation requires `read` permission for the API and the collection (e.g. `*:*:read`, `api:*:read`, `*:treatments:read`, `api:treatments:read`).\n\nThe only exception is the `settings` collection which requires `admin` permission (`api:settings:admin`), because the settings of each application should be isolated and kept secret. You need to know the concrete identifier to access the app's settings.",
+ "operationId": "SEARCH",
+ "parameters": [
+ {
+ "name": "collection",
+ "in": "path",
+ "description": "Collection to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramCollection"
+ }
+ },
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "filter_parameters",
+ "in": "query",
+ "description": "Any number of filtering operators.\n\nEach filtering operator has name like `$`, e.g. `carbs$gt=2` which represents filtering rule \"The field carbs must be present and greater than 2\".\n\nYou can choose from operators:\n\n`eq`=equals, `insulin$eq=1.5`\n\n`ne`=not equals, `insulin$ne=1.5`\n\n`gt`=greater than, `carbs$gt=30`\n\n`gte`=greater than or equal, `carbs$gte=30`\n\n`lt`=less than, `carbs$lt=30`\n\n`lte`=less than or equal, `carbs$lte=30`\n\n`in`=in specified set, `type$in=sgv|mbg|cal`\n\n`nin`=not in specified set, `eventType$nin=Temp%20Basal|Temporary%20Target`\n\n`re`=regex pattern, `eventType$re=Temp.%2A`\n\nWhen filtering by field `date`, `created_at`, `srvModified` or `srvCreated`, you can choose from three input formats\n- Unix epoch in milliseconds (1525383610088)\n- Unix epoch in seconds (1525383610)\n- ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')\n\nThe date is always queried in a normalized form - UTC with zero offset and with the correct format (1525383610088 for `date`, '2018-05-03T21:40:10.088Z' for `created_at`).",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "sort",
+ "in": "query",
+ "description": "Field name by which the sorting of documents is performed. This parameter cannot be combined with `sort$desc` parameter.",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "sort$desc",
+ "in": "query",
+ "description": "Field name by which the descending (reverse) sorting of documents is performed. This parameter cannot be combined with `sort` parameter.",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Maximum number of documents to get in result array",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "minimum": 1,
+ "type": "integer",
+ "example": 100
+ }
+ },
+ {
+ "name": "skip",
+ "in": "query",
+ "description": "Number of documents to skip from collection query before loading them into result array (used for pagination)",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "minimum": 0,
+ "type": "integer",
+ "example": 0,
+ "default": 0
+ }
+ },
+ {
+ "name": "fields",
+ "in": "query",
+ "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string",
+ "default": "_all"
+ },
+ "examples": {
+ "all": {
+ "summary": "All fields will be returned (default behaviour)",
+ "value": "_all"
+ },
+ "customSet": {
+ "summary": "Only fields date and insulin will be returned",
+ "value": "date,insulin"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful operation returning array of documents matching the filtering criteria",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "text/csv": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "Successful operation - no documents matching the filtering criteria"
+ },
+ "400": {
+ "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present."
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404": {
+ "description": "The collection or document specified was not found."
+ },
+ "406": {
+ "description": "The requested content type (in `Accept` header) is not supported."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ },
+ "post": {
+ "tags": [
+ "generic"
+ ],
+ "summary": "CREATE: Inserts a new document into the collection",
+ "description": "Using this operation you can insert new documents into collection. Normally the operation ends with 201 HTTP status code, `Last-Modified` and `Location` headers specified and with an empty response content. `identifier` can be parsed from the `Location` response header.\n\nWhen the document to post is marked as a duplicate (using rules described at `API3_DEDUP_FALLBACK_ENABLED` switch), the update operation takes place instead of inserting. In this case the original document in the collection is found and it gets updated by the actual operation POST body. Finally the operation ends with 204 HTTP status code along with `Last-Modified` and correct `Location` headers.\n\nThis operation provides autopruning of the collection (if autopruning is enabled).\n\nThis operation requires `create` (and/or `update` for deduplication) permission for the API and the collection (e.g. `api:treatments:create` and `api:treatments:update`)",
+ "parameters": [
+ {
+ "name": "collection",
+ "in": "path",
+ "description": "Collection to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramCollection"
+ }
+ },
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "JSON with new document to insert",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentToPost"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "201": {
+ "description": "Successfully created a new document in collection",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ },
+ "Location": {
+ "$ref": "#/components/schemas/headerLocation"
+ }
+ }
+ },
+ "204": {
+ "description": "Successfully finished operation",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ },
+ "Location": {
+ "$ref": "#/components/schemas/headerLocation"
+ }
+ }
+ },
+ "400": {
+ "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present."
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404": {
+ "description": "The collection or document specified was not found."
+ },
+ "422": {
+ "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ }
+ },
+ "/{collection}/{identifier}": {
+ "get": {
+ "tags": [
+ "generic"
+ ],
+ "summary": "READ: Retrieves a single document from the collection",
+ "description": "Basically this operation looks for a document matching the `identifier` field returning 200 or 404 HTTP status code.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code with empty response content is to be returned.\n\nWhen `If-Modified-Since` header is used and its value is greater than the timestamp of the document in the collection, 304 HTTP status code with empty response content is returned. It means that the document has not been modified on server since the last retrieval to client side. With `If-Modified-Since` header and less or equal timestamp `srvModified` a normal 200 HTTP status with full response is returned.\n\nThis operation requires `read` permission for the API and the collection (e.g. `api:treatments:read`)",
+ "parameters": [
+ {
+ "name": "collection",
+ "in": "path",
+ "description": "Collection to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramCollection"
+ }
+ },
+ {
+ "name": "identifier",
+ "in": "path",
+ "description": "Identifier of the document to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramIdentifier"
+ }
+ },
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "If-Modified-Since",
+ "in": "header",
+ "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Modified-Since: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "fields",
+ "in": "query",
+ "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string",
+ "default": "_all"
+ },
+ "examples": {
+ "all": {
+ "summary": "All fields will be returned (default behaviour)",
+ "value": "_all"
+ },
+ "customSet": {
+ "summary": "Only fields date and insulin will be returned",
+ "value": "date,insulin"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "The document has been succesfully found and its JSON form returned in the response content.",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ }
+ },
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Document"
+ }
+ },
+ "text/csv": {
+ "schema": {
+ "$ref": "#/components/schemas/Document"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Document"
+ }
+ }
+ }
+ },
+ "304": {
+ "description": "The document has not been modified on the server since timestamp specified in If-Modified-Since header",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ }
+ }
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404": {
+ "description": "The collection or document specified was not found."
+ },
+ "406": {
+ "description": "The requested content type (in `Accept` header) is not supported."
+ },
+ "410": {
+ "description": "The requested document has already been deleted."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ },
+ "put": {
+ "tags": [
+ "generic"
+ ],
+ "summary": "UPDATE: Updates a document in the collection",
+ "description": "Normally the document with the matching `identifier` will be replaced in the collection by the whole JSON request body and 204 HTTP status code will be returned with empty response body.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code with empty response content is to be returned.\n\nWhen no document with `identifier` has been found in the collection, then an insert operation takes place instead of updating. Finally 201 HTTP status code is returned with only `Last-Modified` header (`identifier` is already known from the path parameter).\n\nYou can also specify `If-Unmodified-Since` request header including your timestamp of document's last modification. If the document has been modified by somebody else on the server afterwards (and you do not know about it), the 412 HTTP status code is returned cancelling the update operation. You can use this feature to prevent race condition problems.\n\nThis operation provides autopruning of the collection (if autopruning is enabled).\n\nThis operation requires `update` (and/or `create`) permission for the API and the collection (e.g. `api:treatments:update` and `api:treatments:create`)",
+ "parameters": [
+ {
+ "name": "collection",
+ "in": "path",
+ "description": "Collection to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramCollection"
+ }
+ },
+ {
+ "name": "identifier",
+ "in": "path",
+ "description": "Identifier of the document to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramIdentifier"
+ }
+ },
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "If-Unmodified-Since",
+ "in": "header",
+ "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Unmodified-Since: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "JSON of new version of document (`identifier` in JSON is ignored if present)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentToPost"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "201": {
+ "description": "Successfully created a new document in collection",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ }
+ }
+ },
+ "204": {
+ "description": "Successfully finished operation",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ },
+ "Location": {
+ "$ref": "#/components/schemas/headerLocation"
+ }
+ }
+ },
+ "400": {
+ "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present."
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404": {
+ "description": "The collection or document specified was not found."
+ },
+ "410": {
+ "description": "The requested document has already been deleted."
+ },
+ "412": {
+ "description": "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header)."
+ },
+ "422": {
+ "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ },
+ "delete": {
+ "tags": [
+ "generic"
+ ],
+ "summary": "DELETE: Deletes a document from the collection",
+ "description": "If the document has already been deleted, the operation will succeed anyway. Normally, documents are not really deleted from the collection but they are only marked as deleted. For special cases the deletion can be irreversible using `permanent` parameter.\n\nThis operation provides autopruning of the collection (if autopruning is enabled).\n\nThis operation requires `delete` permission for the API and the collection (e.g. `api:treatments:delete`)",
+ "parameters": [
+ {
+ "name": "collection",
+ "in": "path",
+ "description": "Collection to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramCollection"
+ }
+ },
+ {
+ "name": "identifier",
+ "in": "path",
+ "description": "Identifier of the document to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramIdentifier"
+ }
+ },
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "permanent",
+ "in": "query",
+ "description": "If true, the deletion will be irreversible and it will not appear in `HISTORY` operation. Normally there is no reason for setting this flag.",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "Successful operation - empty response"
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404": {
+ "description": "The collection or document specified was not found."
+ },
+ "422": {
+ "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ },
+ "patch": {
+ "tags": [
+ "generic"
+ ],
+ "summary": "PATCH: Partially updates document in the collection",
+ "description": "Normally the document with the matching `identifier` will be retrieved from the collection and it will be patched by all specified fields from the JSON request body. Finally 204 HTTP status code will be returned with empty response body.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code with empty response content is to be returned.\n\nWhen no document with `identifier` has been found in the collection, then the operation ends with 404 HTTP status code.\n\nYou can also specify `If-Unmodified-Since` request header including your timestamp of document's last modification. If the document has been modified by somebody else on the server afterwards (and you do not know about it), the 412 HTTP status code is returned cancelling the update operation. You can use this feature to prevent race condition problems.\n\n`PATCH` operation can save some bandwidth for incremental document updates in comparison with `GET` - `UPDATE` operation sequence.\n\nWhile patching the document, the field `modifiedBy` is automatically set to the authorized subject's name.\n\nThis operation provides autopruning of the collection (if autopruning is enabled).\n\nThis operation requires `update` permission for the API and the collection (e.g. `api:treatments:update`)",
+ "parameters": [
+ {
+ "name": "collection",
+ "in": "path",
+ "description": "Collection to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramCollection"
+ }
+ },
+ {
+ "name": "identifier",
+ "in": "path",
+ "description": "Identifier of the document to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramIdentifier"
+ }
+ },
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "If-Unmodified-Since",
+ "in": "header",
+ "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Unmodified-Since: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "requestBody": {
+ "description": "JSON of new version of document (`identifier` in JSON is ignored if present)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentToPost"
+ }
+ }
+ },
+ "required": true
+ },
+ "responses": {
+ "204": {
+ "description": "Successfully finished operation",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ },
+ "Location": {
+ "$ref": "#/components/schemas/headerLocation"
+ }
+ }
+ },
+ "400": {
+ "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present."
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404": {
+ "description": "The collection or document specified was not found."
+ },
+ "410": {
+ "description": "The requested document has already been deleted."
+ },
+ "412": {
+ "description": "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header)."
+ },
+ "422": {
+ "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ }
+ },
+ "/{collection}/history": {
+ "get": {
+ "tags": [
+ "generic"
+ ],
+ "summary": "HISTORY: Retrieves incremental changes since timestamp",
+ "description": "HISTORY operation is intended for continuous data synchronization with other systems.\nEvery insertion, update and deletion will be included in the resulting JSON array of documents (since timestamp in `Last-Modified` request header value). All changes are listed chronologically in response with 200 HTTP status code. The maximum listed `srvModified` timestamp is also stored in `Last-Modified` and `ETag` response headers that you can use for future, directly following synchronization. You can also limit the array's length using `limit` parameter.\n\nDeleted documents will appear with `isValid` = `false` field.\n\nWhen there is no change detected since the timestamp the operation ends with 204 HTTP status code and empty response content.\n\nHISTORY operation has a fallback mechanism in place for documents, which were not created by API v3. For such documents `srvModified` is virtually assigned from the `date` field (for `entries` collection) or from the `created_at` field (for other collections).\n\nThis operation requires `read` permission for the API and the collection (e.g. `api:treatments:read`)\n\nThe only exception is the `settings` collection which requires `admin` permission (`api:settings:admin`), because the settings of each application should be isolated and kept secret. You need to know the concrete identifier to access the app's settings.",
+ "operationId": "HISTORY",
+ "parameters": [
+ {
+ "name": "collection",
+ "in": "path",
+ "description": "Collection to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramCollection"
+ }
+ },
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "Last-Modified",
+ "in": "header",
+ "description": "Starting timestamp (defined with respect to server's clock) since which the changes in documents are to be listed, formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nExample:\n\n
Last-Modified: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Maximum number of documents to get in result array",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "minimum": 1,
+ "type": "integer",
+ "example": 100
+ }
+ },
+ {
+ "name": "fields",
+ "in": "query",
+ "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string",
+ "default": "_all"
+ },
+ "examples": {
+ "all": {
+ "summary": "All fields will be returned (default behaviour)",
+ "value": "_all"
+ },
+ "customSet": {
+ "summary": "Only fields date and insulin will be returned",
+ "value": "date,insulin"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Changed documents since specified timestamp",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModifiedMaximum"
+ },
+ "ETag": {
+ "$ref": "#/components/schemas/headerEtagLastModifiedMaximum"
+ }
+ },
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "text/csv": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "No changes detected"
+ },
+ "400": {
+ "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present."
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404": {
+ "description": "The collection or document specified was not found."
+ },
+ "406": {
+ "description": "The requested content type (in `Accept` header) is not supported."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ }
+ },
+ "/{collection}/history/{lastModified}": {
+ "get": {
+ "tags": [
+ "generic"
+ ],
+ "summary": "HISTORY: Retrieves incremental changes since timestamp",
+ "description": "This HISTORY operation variant is more precise than the previous one with `Last-Modified` request HTTP header), because it does not loose milliseconds precision.\n\nSince this variant queries for changed documents by timestamp precisely and exclusively, the last modified document does not repeat itself in following calls. That is the reason why is this variant more suitable for continuous synchronization with other systems.\n\nThis variant behaves quite the same as the previous one in all other aspects.",
+ "operationId": "HISTORY2",
+ "parameters": [
+ {
+ "name": "collection",
+ "in": "path",
+ "description": "Collection to which the operation is targeted",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "$ref": "#/components/schemas/paramCollection"
+ }
+ },
+ {
+ "name": "lastModified",
+ "in": "path",
+ "description": "Starting timestamp (in UNIX epoch format, defined with respect to server's clock) since which the changes in documents are to be listed. Query for modified documents is made using \"greater than\" operator (not including equal timestamps).",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "limit",
+ "in": "query",
+ "description": "Maximum number of documents to get in result array",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "minimum": 1,
+ "type": "integer",
+ "example": 100
+ }
+ },
+ {
+ "name": "fields",
+ "in": "query",
+ "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string",
+ "default": "_all"
+ },
+ "examples": {
+ "all": {
+ "summary": "All fields will be returned (default behaviour)",
+ "value": "_all"
+ },
+ "customSet": {
+ "summary": "Only fields date and insulin will be returned",
+ "value": "date,insulin"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Changed documents since specified timestamp",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModifiedMaximum"
+ },
+ "ETag": {
+ "$ref": "#/components/schemas/headerEtagLastModifiedMaximum"
+ }
+ },
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "text/csv": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ }
+ }
+ },
+ "204": {
+ "description": "No changes detected"
+ },
+ "400": {
+ "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present."
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404": {
+ "description": "The collection or document specified was not found."
+ },
+ "406": {
+ "description": "The requested content type (in `Accept` header) is not supported."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ }
+ },
+ "/version": {
+ "get": {
+ "tags": [
+ "other"
+ ],
+ "summary": "VERSION: Returns actual version information",
+ "description": "No authentication is needed for this commnad (it is public)",
+ "responses": {
+ "200": {
+ "description": "Successful response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Version"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/status": {
+ "get": {
+ "tags": [
+ "other"
+ ],
+ "summary": "STATUS: Returns actual version information and all permissions granted for API",
+ "description": "This operation requires authorization in contrast with VERSION operation.",
+ "responses": {
+ "200": {
+ "description": "Successful response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Status"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ }
+ },
+ "/lastModified": {
+ "get": {
+ "tags": [
+ "other"
+ ],
+ "summary": "LAST MODIFIED: Retrieves timestamp of the last modification of every collection",
+ "description": "LAST MODIFIED operation inspects collections separately (in parallel) and for each of them it finds the date of any last modification (insertion, update, deletion).\nNot only `srvModified`, but also `date` and `created_at` fields are inspected (as a fallback to previous API).\n\nThis operation requires `read` permission for the API and the collections (e.g. `api:treatments:read`). For each collection the permission is checked separately, you will get timestamps only for those collections that you have access to.",
+ "operationId": "LAST-MODIFIED",
+ "parameters": [
+ {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful operation returning the timestamps",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LastModifiedResult"
+ }
+ }
+ }
+ },
+ "401": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ }
+ },
+ "security": [
+ {
+ "apiKeyAuth": []
+ }
+ ]
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "headerLocation": {
+ "type": "string",
+ "description": "Location of document - the relative part of URL. This can be used to parse the identifier of just created document.\nExample=/api/v3/treatments/53409478-105f-11e9-ab14-d663bd873d93"
+ },
+ "headerLastModified": {
+ "type": "string",
+ "description": "Timestamp of the last document modification on the server, formatted as\n', :: GMT'.\nThis field is relevant only for documents which were somehow modified by API v3 (inserted, updated or deleted) and it was generated using server's clock.\nExample='Wed, 17 Oct 2018 05:13:00 GMT'"
+ },
+ "headerLastModifiedMaximum": {
+ "type": "string",
+ "description": "The latest (maximum) `srvModified` field of all returning documents, formatted as\n', :: GMT'.\nExample='Wed, 17 Oct 2018 05:13:00 GMT'"
+ },
+ "headerEtagLastModifiedMaximum": {
+ "type": "string",
+ "description": "The latest (maximum) `srvModified` field of all returning documents. This header does not loose milliseconds from the date (unlike the `Last-Modified` header).\nExample='W/\"1525383610088\"'"
+ },
+ "paramCollection": {
+ "type": "string",
+ "example": "treatments",
+ "enum": [
+ "devicestatus",
+ "entries",
+ "food",
+ "profile",
+ "settings",
+ "treatments"
+ ]
+ },
+ "paramIdentifier": {
+ "type": "string",
+ "example": "53409478-105f-11e9-ab14-d663bd873d93"
+ },
+ "DocumentBase": {
+ "required": [
+ "app",
+ "date"
+ ],
+ "properties": {
+ "identifier": {
+ "type": "string",
+ "description": "Main addressing, required field that identifies document in the collection.\n\nThe client should not create the identifier, the server automatically assigns it when the document is inserted.\n\nThe server calculates the identifier in such a way that duplicate records are automatically merged (deduplicating is made by `date`, `device` and `eventType` fields).\n\nThe best practise for all applications is not to loose identifiers from received documents, but save them carefully for other consumer applications/systems.\n\nAPI v3 has a fallback mechanism in place, for documents without `identifier` field the `identifier` is set to internal `_id`, when reading or addressing these documents.\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "example": "53409478-105f-11e9-ab14-d663bd873d93"
+ },
+ "date": {
+ "type": "integer",
+ "description": "Required timestamp when the record or event occured, you can choose from three input formats\n- Unix epoch in milliseconds (1525383610088)\n- Unix epoch in seconds (1525383610)\n- ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')\n\nThe date is always stored in a normalized form - UTC with zero offset. If UTC offset was present, it is going to be set in the `utcOffset` field.\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "format": "int64",
+ "example": 1525383610088
+ },
+ "utcOffset": {
+ "type": "integer",
+ "description": "Local UTC offset (timezone) of the event in minutes. This field can be set either directly by the client (in the incoming document) or it is automatically parsed from the `date` field.\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "example": 120
+ },
+ "app": {
+ "type": "string",
+ "description": "Application or system in which the record was entered by human or device for the first time.\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "example": "xdrip"
+ },
+ "device": {
+ "type": "string",
+ "description": "The device from which the data originated (including serial number of the device, if it is relevant and safe).\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "example": "dexcom G5"
+ },
+ "_id": {
+ "type": "string",
+ "description": "Internally assigned database id. This field is for internal server purposes only, clients communicate with API by using identifier field.",
+ "example": "58e9dfbc166d88cc18683aac"
+ },
+ "srvCreated": {
+ "type": "integer",
+ "description": "The server's timestamp of document insertion into the database (Unix epoch in ms). This field appears only for documents which were inserted by API v3.\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "format": "int64",
+ "example": 1525383610088
+ },
+ "subject": {
+ "type": "string",
+ "description": "Name of the security subject (within Nightscout scope) which has created the document. This field is automatically set by the server from the passed token or JWT.\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "example": "uploader"
+ },
+ "srvModified": {
+ "type": "integer",
+ "description": "The server's timestamp of the last document modification in the database (Unix epoch in ms). This field appears only for documents which were somehow modified by API v3 (inserted, updated or deleted).\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "format": "int64",
+ "example": 1525383610088
+ },
+ "modifiedBy": {
+ "type": "string",
+ "description": "Name of the security subject (within Nightscout scope) which has patched or deleted the document for the last time. This field is automatically set by the server.\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "example": "admin"
+ },
+ "isValid": {
+ "type": "boolean",
+ "description": "A flag set by the server only for deleted documents. This field appears only within history operation and for documents which were deleted by API v3 (and they always have a false value)\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "example": false
+ },
+ "isReadOnly": {
+ "type": "boolean",
+ "description": "A flag set by client that locks the document from any changes. Every document marked with `isReadOnly=true` is forever immutable and cannot even be deleted.\n\nAny attempt to modify the read-only document will end with status 422 UNPROCESSABLE ENTITY.",
+ "example": true
+ }
+ },
+ "description": "Shared base for all documents"
+ },
+ "DeviceStatus": {
+ "description": "State of physical device, which is a technical part of the whole T1D compensation system",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/DocumentBase"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "some_property": {
+ "type": "string",
+ "description": "..."
+ }
+ }
+ }
+ ]
+ },
+ "Entry": {
+ "description": "Blood glucose measurements and CGM calibrations",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/DocumentBase"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "sgv, mbg, cal, etc"
+ },
+ "sgv": {
+ "type": "number",
+ "description": "The glucose reading. (only available for sgv types)"
+ },
+ "direction": {
+ "type": "string",
+ "description": "Direction of glucose trend reported by CGM. (only available for sgv types)",
+ "example": "\"DoubleDown\", \"SingleDown\", \"FortyFiveDown\", \"Flat\", \"FortyFiveUp\", \"SingleUp\", \"DoubleUp\", \"NOT COMPUTABLE\", \"RATE OUT OF RANGE\" for xdrip"
+ },
+ "noise": {
+ "type": "number",
+ "description": "Noise level at time of reading. (only available for sgv types)"
+ },
+ "filtered": {
+ "type": "number",
+ "description": "The raw filtered value directly from CGM transmitter. (only available for sgv types)"
+ },
+ "unfiltered": {
+ "type": "number",
+ "description": "The raw unfiltered value directly from CGM transmitter. (only available for sgv types)"
+ },
+ "rssi": {
+ "type": "number",
+ "description": "The signal strength from CGM transmitter. (only available for sgv types)"
+ },
+ "units": {
+ "type": "string",
+ "description": "The units for the glucose value, mg/dl or mmol/l. It is strongly recommended to fill in this field.",
+ "example": "\"mg\", \"mmol\""
+ }
+ }
+ }
+ ]
+ },
+ "Food": {
+ "description": "Nutritional values of food",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/DocumentBase"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "food": {
+ "type": "string",
+ "description": "food, quickpick"
+ },
+ "category": {
+ "type": "string",
+ "description": "Name for a group of related records"
+ },
+ "subcategory": {
+ "type": "string",
+ "description": "Name for a second level of groupping"
+ },
+ "name": {
+ "type": "string",
+ "description": "Name of the food described"
+ },
+ "portion": {
+ "type": "number",
+ "description": "Number of units (e.g. grams) of the whole portion described"
+ },
+ "unit": {
+ "type": "string",
+ "description": "Unit for the portion",
+ "example": "\"g\", \"ml\", \"oz\""
+ },
+ "carbs": {
+ "type": "number",
+ "description": "Amount of carbs in the portion in grams"
+ },
+ "fat": {
+ "type": "number",
+ "description": "Amount of fat in the portion in grams"
+ },
+ "protein": {
+ "type": "number",
+ "description": "Amount of proteins in the portion in grams"
+ },
+ "energy": {
+ "type": "number",
+ "description": "Amount of energy in the portion in kJ"
+ },
+ "gi": {
+ "type": "number",
+ "description": "Glycemic index (1=low, 2=medium, 3=high)"
+ },
+ "hideafteruse": {
+ "type": "boolean",
+ "description": "Flag used for quickpick"
+ },
+ "hidden": {
+ "type": "boolean",
+ "description": "Flag used for quickpick"
+ },
+ "position": {
+ "type": "number",
+ "description": "Ordering field for quickpick"
+ },
+ "portions": {
+ "type": "number",
+ "description": "component multiplier if defined inside quickpick compound"
+ },
+ "foods": {
+ "type": "array",
+ "description": "Neighbour documents (from food collection) that together make a quickpick compound",
+ "items": {
+ "$ref": "#/components/schemas/Food"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Profile": {
+ "description": "Parameters describing body functioning relative to T1D + compensation parameters",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/DocumentBase"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "some_property": {
+ "type": "string",
+ "description": "..."
+ }
+ }
+ }
+ ]
+ },
+ "Settings": {
+ "description": "A document representing persisted settings of some application or system (it could by Nightscout itself as well). This pack of options serves as a backup or as a shared centralized storage for multiple client instances. It is a probably good idea to `PATCH` the document instead of `UPDATE` operation, e.g. when changing one settings option in a client application.\n\n`identifier` represents a client application name here, e.g. `xdrip` or `aaps`.\n\n`Settings` collection has a more specific authorization required. For the `SEARCH` operation within this collection, you need an `admin` permission, such as `api:settings:admin`. The goal is to isolate individual client application settings.",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/DocumentBase"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "some_property": {
+ "type": "string",
+ "description": "..."
+ }
+ }
+ }
+ ]
+ },
+ "Treatment": {
+ "description": "T1D compensation action",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/DocumentBase"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "eventType": {
+ "type": "string",
+ "description": "The type of treatment event.\n\nNote: this field is immutable by the client (it cannot be updated or patched)",
+ "example": "\"BG Check\", \"Snack Bolus\", \"Meal Bolus\", \"Correction Bolus\", \"Carb Correction\", \"Combo Bolus\", \"Announcement\", \"Note\", \"Question\", \"Exercise\", \"Site Change\", \"Sensor Start\", \"Sensor Change\", \"Pump Battery Change\", \"Insulin Change\", \"Temp Basal\", \"Profile Switch\", \"D.A.D. Alert\", \"Temporary Target\", \"OpenAPS Offline\", \"Bolus Wizard\""
+ },
+ "glucose": {
+ "type": "string",
+ "description": "Current glucose."
+ },
+ "glucoseType": {
+ "type": "string",
+ "description": "Method used to obtain glucose, Finger or Sensor.",
+ "example": "\"Sensor\", \"Finger\", \"Manual\""
+ },
+ "units": {
+ "type": "string",
+ "description": "The units for the glucose value, mg/dl or mmol/l. It is strongly recommended to fill in this field when `glucose` is entered.",
+ "example": "\"mg/dl\", \"mmol/l\""
+ },
+ "carbs": {
+ "type": "number",
+ "description": "Amount of carbs given."
+ },
+ "protein": {
+ "type": "number",
+ "description": "Amount of protein given."
+ },
+ "fat": {
+ "type": "number",
+ "description": "Amount of fat given."
+ },
+ "insulin": {
+ "type": "number",
+ "description": "Amount of insulin, if any."
+ },
+ "duration": {
+ "type": "number",
+ "description": "Duration in minutes."
+ },
+ "preBolus": {
+ "type": "number",
+ "description": "How many minutes the bolus was given before the meal started."
+ },
+ "splitNow": {
+ "type": "number",
+ "description": "Immediate part of combo bolus (in percent)."
+ },
+ "splitExt": {
+ "type": "number",
+ "description": "Extended part of combo bolus (in percent)."
+ },
+ "percent": {
+ "type": "number",
+ "description": "Eventual basal change in percent."
+ },
+ "absolute": {
+ "type": "number",
+ "description": "Eventual basal change in absolute value (insulin units per hour)."
+ },
+ "targetTop": {
+ "type": "number",
+ "description": "Top limit of temporary target."
+ },
+ "targetBottom": {
+ "type": "number",
+ "description": "Bottom limit of temporary target."
+ },
+ "profile": {
+ "type": "string",
+ "description": "Name of the profile to which the pump has been switched."
+ },
+ "reason": {
+ "type": "string",
+ "description": "For example the reason why the profile has been switched or why the temporary target has been set."
+ },
+ "notes": {
+ "type": "string",
+ "description": "Description/notes of treatment."
+ },
+ "enteredBy": {
+ "type": "string",
+ "description": "Who entered the treatment."
+ }
+ }
+ }
+ ]
+ },
+ "DocumentToPost": {
+ "type": "object",
+ "description": "Single document",
+ "example": {
+ "identifier": "53409478-105f-11e9-ab14-d663bd873d93",
+ "date": 1532936118000,
+ "utcOffset": 120,
+ "carbs": 10,
+ "insulin": 1,
+ "eventType": "Snack Bolus",
+ "app": "xdrip",
+ "subject": "uploader"
+ },
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/DeviceStatus"
+ },
+ {
+ "$ref": "#/components/schemas/Entry"
+ },
+ {
+ "$ref": "#/components/schemas/Food"
+ },
+ {
+ "$ref": "#/components/schemas/Profile"
+ },
+ {
+ "$ref": "#/components/schemas/Settings"
+ },
+ {
+ "$ref": "#/components/schemas/Treatment"
+ }
+ ]
+ },
+ "Document": {
+ "type": "object",
+ "description": "Single document",
+ "example": {
+ "identifier": "53409478-105f-11e9-ab14-d663bd873d93",
+ "date": 1532936118000,
+ "utcOffset": 120,
+ "carbs": 10,
+ "insulin": 1,
+ "eventType": "Snack Bolus",
+ "srvCreated": 1532936218000,
+ "srvModified": 1532936218000,
+ "app": "xdrip",
+ "subject": "uploader",
+ "modifiedBy": "admin"
+ },
+ "xml": {
+ "name": "item"
+ },
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/DeviceStatus"
+ },
+ {
+ "$ref": "#/components/schemas/Entry"
+ },
+ {
+ "$ref": "#/components/schemas/Food"
+ },
+ {
+ "$ref": "#/components/schemas/Profile"
+ },
+ {
+ "$ref": "#/components/schemas/Settings"
+ },
+ {
+ "$ref": "#/components/schemas/Treatment"
+ }
+ ]
+ },
+ "DeviceStatusArray": {
+ "type": "array",
+ "description": "Array of documents",
+ "items": {
+ "$ref": "#/components/schemas/DeviceStatus"
+ }
+ },
+ "EntryArray": {
+ "type": "array",
+ "description": "Array of documents",
+ "items": {
+ "$ref": "#/components/schemas/Entry"
+ }
+ },
+ "FoodArray": {
+ "type": "array",
+ "description": "Array of documents",
+ "items": {
+ "$ref": "#/components/schemas/Food"
+ }
+ },
+ "ProfileArray": {
+ "type": "array",
+ "description": "Array of documents",
+ "items": {
+ "$ref": "#/components/schemas/Profile"
+ }
+ },
+ "SettingsArray": {
+ "type": "array",
+ "description": "Array of settings",
+ "items": {
+ "$ref": "#/components/schemas/Settings"
+ }
+ },
+ "TreatmentArray": {
+ "type": "array",
+ "description": "Array of documents",
+ "items": {
+ "$ref": "#/components/schemas/Treatment"
+ }
+ },
+ "DocumentArray": {
+ "type": "object",
+ "xml": {
+ "name": "items"
+ },
+ "oneOf": [
+ {
+ "$ref": "#/components/schemas/DeviceStatusArray"
+ },
+ {
+ "$ref": "#/components/schemas/EntryArray"
+ },
+ {
+ "$ref": "#/components/schemas/FoodArray"
+ },
+ {
+ "$ref": "#/components/schemas/ProfileArray"
+ },
+ {
+ "$ref": "#/components/schemas/SettingsArray"
+ },
+ {
+ "$ref": "#/components/schemas/TreatmentArray"
+ }
+ ]
+ },
+ "Version": {
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "string",
+ "description": "The whole Nightscout instance version",
+ "example": "0.10.2-release-20171201"
+ },
+ "apiVersion": {
+ "type": "string",
+ "description": "API v3 subsystem version",
+ "example": "3.0.0"
+ },
+ "srvDate": {
+ "type": "number",
+ "description": "Actual server date and time in UNIX epoch format",
+ "example": 1532936118000
+ },
+ "storage": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Type of storage engine used",
+ "example": "mongodb"
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the storage engine",
+ "example": "4.0.6"
+ }
+ }
+ }
+ },
+ "description": "Information about versions"
+ },
+ "Status": {
+ "description": "Information about versions and API permissions",
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/Version"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "apiPermissions": {
+ "type": "object",
+ "properties": {
+ "devicestatus": {
+ "type": "string",
+ "example": "crud"
+ },
+ "entries": {
+ "type": "string",
+ "example": "r"
+ },
+ "food": {
+ "type": "string",
+ "example": "crud"
+ },
+ "profile": {
+ "type": "string",
+ "example": "r"
+ },
+ "treatments": {
+ "type": "string",
+ "example": "crud"
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "LastModifiedResult": {
+ "properties": {
+ "srvDate": {
+ "type": "integer",
+ "description": "Actual storage server date (Unix epoch in ms).",
+ "format": "int64",
+ "example": 1556260878776
+ },
+ "collections": {
+ "type": "object",
+ "properties": {
+ "devicestatus": {
+ "type": "integer",
+ "description": "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.",
+ "format": "int64",
+ "example": 1556260760974
+ },
+ "treatments": {
+ "type": "integer",
+ "description": "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.",
+ "format": "int64",
+ "example": 1553374184169
+ },
+ "entries": {
+ "type": "integer",
+ "description": "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.",
+ "format": "int64",
+ "example": 1556260758768
+ },
+ "profile": {
+ "type": "integer",
+ "description": "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.",
+ "format": "int64",
+ "example": 1548524042744
+ }
+ },
+ "description": "Collections which the user have read access to."
+ }
+ },
+ "description": "Result of LAST MODIFIED operation"
+ }
+ },
+ "responses": {
+ "201Created": {
+ "description": "Successfully created a new document in collection",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ }
+ }
+ },
+ "201CreatedLocation": {
+ "description": "Successfully created a new document in collection",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ },
+ "Location": {
+ "$ref": "#/components/schemas/headerLocation"
+ }
+ }
+ },
+ "204NoContent": {
+ "description": "Successfully finished operation",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ }
+ }
+ },
+ "204NoContentLocation": {
+ "description": "Successfully finished operation",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ },
+ "Location": {
+ "$ref": "#/components/schemas/headerLocation"
+ }
+ }
+ },
+ "304NotModified": {
+ "description": "The document has not been modified on the server since timestamp specified in If-Modified-Since header",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ }
+ }
+ },
+ "400BadRequest": {
+ "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present."
+ },
+ "401Unauthorized": {
+ "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy."
+ },
+ "403Forbidden": {
+ "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation."
+ },
+ "404NotFound": {
+ "description": "The collection or document specified was not found."
+ },
+ "406NotAcceptable": {
+ "description": "The requested content type (in `Accept` header) is not supported."
+ },
+ "412PreconditionFailed": {
+ "description": "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header)."
+ },
+ "410Gone": {
+ "description": "The requested document has already been deleted."
+ },
+ "422UnprocessableEntity": {
+ "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)."
+ },
+ "search200": {
+ "description": "Successful operation returning array of documents matching the filtering criteria",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "text/csv": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ }
+ }
+ },
+ "search204": {
+ "description": "Successful operation - no documents matching the filtering criteria"
+ },
+ "read200": {
+ "description": "The document has been succesfully found and its JSON form returned in the response content.",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModified"
+ }
+ },
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Document"
+ }
+ },
+ "text/csv": {
+ "schema": {
+ "$ref": "#/components/schemas/Document"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/Document"
+ }
+ }
+ }
+ },
+ "history200": {
+ "description": "Changed documents since specified timestamp",
+ "headers": {
+ "Last-Modified": {
+ "$ref": "#/components/schemas/headerLastModifiedMaximum"
+ },
+ "ETag": {
+ "$ref": "#/components/schemas/headerEtagLastModifiedMaximum"
+ }
+ },
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "text/csv": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ },
+ "application/xml": {
+ "schema": {
+ "$ref": "#/components/schemas/DocumentArray"
+ }
+ }
+ }
+ },
+ "history204": {
+ "description": "No changes detected"
+ },
+ "lastModified200": {
+ "description": "Successful operation returning the timestamps",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/LastModifiedResult"
+ }
+ }
+ }
+ }
+ },
+ "parameters": {
+ "dateHeader": {
+ "name": "Date",
+ "in": "header",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "nowParam": {
+ "name": "now",
+ "in": "query",
+ "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "integer",
+ "format": "int64"
+ }
+ },
+ "tokenParam": {
+ "name": "token",
+ "in": "query",
+ "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "limitParam": {
+ "name": "limit",
+ "in": "query",
+ "description": "Maximum number of documents to get in result array",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "minimum": 1,
+ "type": "integer",
+ "example": 100
+ }
+ },
+ "skipParam": {
+ "name": "skip",
+ "in": "query",
+ "description": "Number of documents to skip from collection query before loading them into result array (used for pagination)",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "minimum": 0,
+ "type": "integer",
+ "example": 0,
+ "default": 0
+ }
+ },
+ "sortParam": {
+ "name": "sort",
+ "in": "query",
+ "description": "Field name by which the sorting of documents is performed. This parameter cannot be combined with `sort$desc` parameter.",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "sortDescParam": {
+ "name": "sort$desc",
+ "in": "query",
+ "description": "Field name by which the descending (reverse) sorting of documents is performed. This parameter cannot be combined with `sort` parameter.",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "permanentParam": {
+ "name": "permanent",
+ "in": "query",
+ "description": "If true, the deletion will be irreversible and it will not appear in `HISTORY` operation. Normally there is no reason for setting this flag.",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "fieldsParam": {
+ "name": "fields",
+ "in": "query",
+ "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string",
+ "default": "_all"
+ },
+ "examples": {
+ "all": {
+ "summary": "All fields will be returned (default behaviour)",
+ "value": "_all"
+ },
+ "customSet": {
+ "summary": "Only fields date and insulin will be returned",
+ "value": "date,insulin"
+ }
+ }
+ },
+ "filterParams": {
+ "name": "filter_parameters",
+ "in": "query",
+ "description": "Any number of filtering operators.\n\nEach filtering operator has name like `$`, e.g. `carbs$gt=2` which represents filtering rule \"The field carbs must be present and greater than 2\".\n\nYou can choose from operators:\n\n`eq`=equals, `insulin$eq=1.5`\n\n`ne`=not equals, `insulin$ne=1.5`\n\n`gt`=greater than, `carbs$gt=30`\n\n`gte`=greater than or equal, `carbs$gte=30`\n\n`lt`=less than, `carbs$lt=30`\n\n`lte`=less than or equal, `carbs$lte=30`\n\n`in`=in specified set, `type$in=sgv|mbg|cal`\n\n`nin`=not in specified set, `eventType$nin=Temp%20Basal|Temporary%20Target`\n\n`re`=regex pattern, `eventType$re=Temp.%2A`\n\nWhen filtering by field `date`, `created_at`, `srvModified` or `srvCreated`, you can choose from three input formats\n- Unix epoch in milliseconds (1525383610088)\n- Unix epoch in seconds (1525383610)\n- ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')\n\nThe date is always queried in a normalized form - UTC with zero offset and with the correct format (1525383610088 for `date`, '2018-05-03T21:40:10.088Z' for `created_at`).",
+ "required": false,
+ "style": "form",
+ "explode": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "lastModifiedRequiredHeader": {
+ "name": "Last-Modified",
+ "in": "header",
+ "description": "Starting timestamp (defined with respect to server's clock) since which the changes in documents are to be listed, formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nExample:\n\n
Last-Modified: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": true,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "ifModifiedSinceHeader": {
+ "name": "If-Modified-Since",
+ "in": "header",
+ "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Modified-Since: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ "ifUnmodifiedSinceHeader": {
+ "name": "If-Unmodified-Since",
+ "in": "header",
+ "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Unmodified-Since: Wed, 17 Oct 2018 05:13:00 GMT
",
+ "required": false,
+ "style": "simple",
+ "explode": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
+ "securitySchemes": {
+ "accessToken": {
+ "type": "apiKey",
+ "description": "Add token as query item in the URL or as HTTP header. You can manage access token in `/admin`.\nEach operation requires a specific permission that has to be granted (via security role) to the security subject, which was authenticated by `token` parameter/header or `JWT`. E.g. for creating new `devicestatus` document via API you need `api:devicestatus:create` permission.",
+ "name": "token",
+ "in": "query"
+ },
+ "jwtoken": {
+ "type": "http",
+ "description": "Use this if you know the temporary json webtoken.",
+ "scheme": "bearer",
+ "bearerFormat": "JWT"
+ }
+ }
+ }
+}
diff --git a/lib/authorization/storage.js b/lib/authorization/storage.js
index c032018d170..d602470add6 100644
--- a/lib/authorization/storage.js
+++ b/lib/authorization/storage.js
@@ -210,16 +210,28 @@ function init (env, ctx) {
if (!accessToken) return null;
- var split_token = accessToken.split('-');
- var prefix = split_token ? _.last(split_token) : '';
- if (prefix.length < 16) {
- return null;
- }
+ function checkToken(accessToken) {
+ var split_token = accessToken.split('-');
+ var prefix = split_token ? _.last(split_token) : '';
- return _.find(storage.subjects, function matches (subject) {
- return subject.accessTokenDigest.indexOf(accessToken) === 0 || subject.digest.indexOf(prefix) === 0;
- });
+ if (prefix.length < 16) {
+ return null;
+ }
+
+ return _.find(storage.subjects, function matches (subject) {
+ return subject.accessTokenDigest.indexOf(accessToken) === 0 || subject.digest.indexOf(prefix) === 0;
+ });
+ }
+
+ if (!Array.isArray(accessToken)) accessToken = [accessToken];
+
+ for (let i=0; i < accessToken.length; i++) {
+ const subject = checkToken(accessToken[i]);
+ if (subject) return subject;
+ }
+
+ return null;
};
storage.doesAccessTokenExist = function doesAccessTokenExist(accessToken) {
diff --git a/lib/client/clock-client.js b/lib/client/clock-client.js
index 891f10d57d5..73ac9c3baca 100644
--- a/lib/client/clock-client.js
+++ b/lib/client/clock-client.js
@@ -1,53 +1,55 @@
'use strict';
-const browserSettings = require('./browser-settings');
-
+var browserSettings = require('./browser-settings');
var client = {};
+var latestProperties = {};
client.settings = browserSettings(client, window.serverSettings, $);
-//console.log('settings', client.settings);
-// client.settings now contains all settings
-
client.query = function query () {
- console.log('query');
var parts = (location.search || '?').substring(1).split('&');
var token = '';
- parts.forEach(function (val) {
+ parts.forEach(function(val) {
if (val.startsWith('token=')) {
token = val.substring('token='.length);
}
});
var secret = localStorage.getItem('apisecrethash');
- var src = '/api/v1/entries.json?find[type]=sgv&count=3&t=' + new Date().getTime();
+ var src = '/api/v2/properties'; // Use precalculated data from the backend
if (secret) {
- src += '&secret=' + secret;
+ var s = '?secret=' + secret;
+ src += s;
} else if (token) {
- src += '&token=' + token;
+ var s2 = '?token=' + token;
+ src += s2;
}
$.ajax(src, {
- success: client.render
+ error: function gotError (err) {
+ console.error(err);
+ }
+ , success: function gotData (data) {
+ latestProperties = data;
+ client.render();
+ }
});
};
-client.render = function render (xhr) {
- console.log('got data', xhr);
+client.render = function render () {
- let rec;
- let delta;
+ if (!latestProperties.bgnow && !latestProperties.bgnow.sgvs) {
+ console.error('BG data not available');
+ return;
+ }
- // Get SGV, calculate DELTA
- xhr.forEach(element => {
- if (element.sgv && !rec) {
- rec = element;
- }
- else if (element.sgv && rec && delta==null) {
- delta = (rec.sgv - element.sgv)/((rec.date - element.date)/(5*60*1000));
- }
- });
+ let rec = latestProperties.bgnow.sgvs[0];
+ let deltaDisplayValue;
+
+ if (latestProperties.delta) {
+ deltaDisplayValue = latestProperties.delta.display;
+ }
let $errorMessage = $('#errorMessage');
let $inner = $('#inner');
@@ -71,15 +73,12 @@ client.render = function render (xhr) {
// Backward compatible
if (face === 'clock-color') {
- face = 'c' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg40-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar30-nl-ag6';
- }
- else if (face === 'clock') {
+ face = 'c' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg35-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar25-nl-ag6';
+ } else if (face === 'clock') {
face = 'bn0-sg40';
- }
- else if (face === 'bgclock') {
- face = 'bn0-sg30-ar18-nl-nl-tm26';
- }
- else if (face === 'config') {
+ } else if (face === 'bgclock') {
+ face = 'b' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg35-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar25-nl-ag6';
+ } else if (face === 'config') {
face = $inner.attr('data-face-config');
$inner.empty();
}
@@ -95,46 +94,19 @@ client.render = function render (xhr) {
if (param === '0') {
bgColor = (faceParams[param].substr(0, 1) === 'c'); // do we want colorful background?
alwaysShowTime = (faceParams[param].substr(1, 1) === 'y'); // always show "stale time" text?
- staleMinutes = (faceParams[param].substr(2,2) - 0 >= 0) ? faceParams[param].substr(2,2) : 13; // threshold value (0=never)
- } else if (!clockCreated){
- let div = '