diff --git a/lib/api3/generic/search/input.js b/lib/api3/generic/search/input.js index dbd37356760..d62213cfbea 100644 --- a/lib/api3/generic/search/input.js +++ b/lib/api3/generic/search/input.js @@ -55,10 +55,34 @@ function parseFilter (req, res) { , operators = ['eq', 'ne', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 're'] ; + // filter_parameters query parameter needs to be split + // into individual parameters before it can be processed + const processedQueryParams = {}; + for (let param in req.query) { if (!Object.prototype.hasOwnProperty.call(req.query, param) || reservedParams.includes(param)) continue; + if (param === 'filter_parameters') { + // filter_parameters are a space separated list of + // $= + // for the purpose of building the filter, we want + // to take each $ as the key for + // the processes query params map + const filterValues = req.query[param].split(' '); + + for (const filterValue of filterValues) { + const filterParts = filterValue.split('='); + + processedQueryParams[filterParts[0]] = filterParts[1]; + } + } + else { + processedQueryParams[param] = req.query[param]; + } + } + + for (let param in processedQueryParams) { let field = param , operator = 'eq' ; @@ -74,7 +98,7 @@ function parseFilter (req, res) { return null; } } - const value = parseValue(field, req.query[param]); + const value = parseValue(field, processedQueryParams[param]); filter.push({ field, operator, value }); } @@ -137,4 +161,4 @@ module.exports = { parseFilter, parseSort, parseSkip -}; \ No newline at end of file +}; diff --git a/lib/api3/storage/mongoCollection/utils.js b/lib/api3/storage/mongoCollection/utils.js index a2f7b16520c..a7ee4e55e09 100644 --- a/lib/api3/storage/mongoCollection/utils.js +++ b/lib/api3/storage/mongoCollection/utils.js @@ -27,6 +27,7 @@ function normalizeDoc (doc) { */ function parseFilter (filterDef, logicalOperator, onlyValid) { let filter = { }; + if (!filterDef) return filter; @@ -39,56 +40,57 @@ function parseFilter (filterDef, logicalOperator, onlyValid) { for (const itemDef of filterDef) { let item; + // Check if a query is already started for given field + if (!filter.hasOwnProperty(itemDef.field)) { + filter[itemDef.field] = {}; + } + switch (itemDef.operator) { case 'eq': - item = itemDef.value; + filter[itemDef.field]['$eq'] = itemDef.value; break; case 'ne': - item = { $ne: itemDef.value }; + filter[itemDef.field]['$ne'] = itemDef.value; break; case 'gt': - item = { $gt: itemDef.value }; + filter[itemDef.field]['$gt'] = itemDef.value; break; case 'gte': - item = { $gte: itemDef.value }; + filter[itemDef.field]['$gte'] = itemDef.value; break; case 'lt': - item = { $lt: itemDef.value }; + filter[itemDef.field]['$lt'] = itemDef.value; break; case 'lte': - item = { $lte: itemDef.value }; + filter[itemDef.field]['$lte'] = itemDef.value; break; case 'in': - item = { $in: itemDef.value.toString().split('|') }; + filter[itemDef.field]['$in'] = itemDef.value.toString().split('|'); break; case 'nin': - item = { $nin: itemDef.value.toString().split('|') }; + filter[itemDef.field]['$nin'] = itemDef.value.toString().split('|'); break; case 're': - item = { $regex: itemDef.value.toString() }; + filter[itemDef.field]['$regex'] = itemDef.value.toString(); break; default: throw new Error('Unsupported or missing filter operator ' + itemDef.operator); - } + } // switch (itemDef.operator) if (logicalOperator === 'or') { - let clause = { }; - clause[itemDef.field] = item; - clauses.push(clause); - } - else { - filter[itemDef.field] = item; + clauses.push(filter); + filter = { }; } - } + } // for (const itemDef of filterDef) if (logicalOperator === 'or') { filter = { $or: clauses }; diff --git a/lib/api3/swagger.json b/lib/api3/swagger.json index 20a8830a214..2c676410c24 100644 --- a/lib/api3/swagger.json +++ b/lib/api3/swagger.json @@ -1,2514 +1,2384 @@ { - "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- 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)
API3_AUTOPRUNE_DEVICESTATUS=60\nAPI3_AUTOPRUNE_ENTRIES=365\nAPI3_AUTOPRUNE_TREATMENTS=120 
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" + "openapi" : "3.0.0", + "info" : { + "contact" : { + "name" : "NS development discussion channel", + "url" : "https://gitter.im/nightscout/public" }, - "license": { - "name": "AGPL 3", - "url": "https://www.gnu.org/licenses/agpl.txt" + "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- 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)
API3_AUTOPRUNE_DEVICESTATUS=60\nAPI3_AUTOPRUNE_ENTRIES=365\nAPI3_AUTOPRUNE_TREATMENTS=120 
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.", + "license" : { + "name" : "AGPL 3", + "url" : "https://www.gnu.org/licenses/agpl.txt" }, - "version": "3.0.4" + "title" : "Nightscout API", + "version" : "3.0.4" }, - "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\nIf successful, HTTP 200 code is returned with JSON array of matching documents as a response content (it may be empty).\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": "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/inline_response_200" + "servers" : [ { + "url" : "/api/v3" + } ], + "tags" : [ { + "description" : "Generic operations with each database collection (devicestatus, entries, food, profile, settings, treatments)", + "name" : "generic" + }, { + "description" : "All other various operations", + "name" : "other" + } ], + "paths" : { + "/{collection}" : { + "get" : { + "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\nIf successful, HTTP 200 code is returned with JSON array of matching documents as a response content (it may be empty).\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" : [ { + "description" : "Collection to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "collection", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramCollection" + }, + "style" : "simple" + }, { + "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`).", + "explode" : false, + "in" : "query", + "name" : "filter_parameters", + "required" : false, + "schema" : { + "items" : { + "type" : "string" + }, + "type" : "array" + }, + "style" : "spaceDelimited" + }, { + "description" : "Field name by which the sorting of documents is performed. This parameter cannot be combined with `sort$desc` parameter.", + "explode" : true, + "in" : "query", + "name" : "sort", + "required" : false, + "schema" : { + "type" : "string" + }, + "style" : "form" + }, { + "description" : "Field name by which the descending (reverse) sorting of documents is performed. This parameter cannot be combined with `sort` parameter.", + "explode" : true, + "in" : "query", + "name" : "sort$desc", + "required" : false, + "schema" : { + "type" : "string" + }, + "style" : "form" + }, { + "description" : "Maximum number of documents to get in result array", + "explode" : true, + "in" : "query", + "name" : "limit", + "required" : false, + "schema" : { + "example" : 100, + "minimum" : 1, + "type" : "integer" + }, + "style" : "form" + }, { + "description" : "Number of documents to skip from collection query before loading them into result array (used for pagination)", + "explode" : true, + "in" : "query", + "name" : "skip", + "required" : false, + "schema" : { + "default" : 0, + "example" : 0, + "minimum" : 0, + "type" : "integer" + }, + "style" : "form" + }, { + "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", + "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" + } + }, + "explode" : true, + "in" : "query", + "name" : "fields", + "required" : false, + "schema" : { + "default" : "_all", + "type" : "string" + }, + "style" : "form" + } ], + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_200_response" } }, - "text/csv": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" + "text/csv" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" } }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" } } - } + }, + "description" : "Successful operation returning array of documents matching the filtering criteria" }, - "400": { - "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_400" + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_400_response" } } - } + }, + "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 JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" } } - } + }, + "description" : "The collection or document specified was not found." }, - "406": { - "description": "The requested content type (in `Accept` header) is not supported.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_406" + "406" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_406_response" } } - } + }, + "description" : "The requested content type (in `Accept` header) is not supported." } }, - "security": [ - { - "jwtoken": [] - } - ] - }, - "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. `identifier` is included in response body or it 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 200 HTTP status code along with `Last-Modified` and correct `Location` headers. The response body then includes `isDeduplication`=`true` and `deduplicatedIdentifier` fields.\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" - } - } - ], - "requestBody": { - "description": "JSON with new document to insert", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentToPost" - } - } - }, - "required": true + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "SEARCH: Search documents from the collection", + "tags" : [ "generic" ] + }, + "post" : { + "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. `identifier` is included in response body or it 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 200 HTTP status code along with `Last-Modified` and correct `Location` headers. The response body then includes `isDeduplication`=`true` and `deduplicatedIdentifier` fields.\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" : [ { + "description" : "Collection to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "collection", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramCollection" + }, + "style" : "simple" + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentToPost" + } + } + }, + "description" : "JSON with new document to insert", + "required" : true }, - "responses": { - "200": { - "description": "Successfully updated a duplicate document in the collection", - "headers": { - "Last-Modified": { - "$ref": "#/components/schemas/headerLastModified" - }, - "Location": { - "$ref": "#/components/schemas/headerLocation" + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_200_response" + } } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_1" - } + "description" : "Successfully updated a duplicate document in the collection", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModified" + }, + "Location" : { + "$ref" : "#/components/schemas/headerLocation" } } }, - "201": { - "description": "Successfully created a new document in collection", - "headers": { - "Last-Modified": { - "$ref": "#/components/schemas/headerLastModified" - }, - "Location": { - "$ref": "#/components/schemas/headerLocation" + "201" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_201_response" + } } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_201" - } + "description" : "Successfully created a new document in collection", + "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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_400" + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_400_response" } } - } + }, + "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 JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" } } - } + }, + "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`).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_422" + "422" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_422_response" } } - } + }, + "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": [ - { - "jwtoken": [] - } - ] + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "CREATE: Inserts a new document into the collection", + "tags" : [ "generic" ] } }, - "/{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 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" - } + "/{collection}/{identifier}" : { + "delete" : { + "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" : [ { + "description" : "Collection to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "collection", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramCollection" + }, + "style" : "simple" + }, { + "description" : "Identifier of the document to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "identifier", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramIdentifier" + }, + "style" : "simple" + }, { + "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.", + "explode" : true, + "in" : "query", + "name" : "permanent", + "required" : false, + "schema" : { + "type" : "boolean" + }, + "style" : "form" + } ], + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__put_200_response" + } + } + }, + "description" : "The request was successfully processed" }, - { - "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" - } + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" + } + } + }, + "description" : "The request was not successfully authenticated using JWT, so that the request cannot continue due to the security policy." }, - { - "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" - } + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" + } + } + }, + "description" : "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." }, - { - "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" + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" + } } - } - } - ], - "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" + }, + "description" : "The collection or document specified was not found." + }, + "422" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_422_response" + } } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_2" + "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" : [ { + "jwtoken" : [ ] + } ], + "summary" : "DELETE: Deletes a document from the collection", + "tags" : [ "generic" ] + }, + "get" : { + "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 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" : [ { + "description" : "Collection to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "collection", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramCollection" + }, + "style" : "simple" + }, { + "description" : "Identifier of the document to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "identifier", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramIdentifier" + }, + "style" : "simple" + }, { + "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
", + "explode" : false, + "in" : "header", + "name" : "If-Modified-Since", + "required" : false, + "schema" : { + "type" : "string" + }, + "style" : "simple" + }, { + "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", + "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" + } + }, + "explode" : true, + "in" : "query", + "name" : "fields", + "required" : false, + "schema" : { + "default" : "_all", + "type" : "string" + }, + "style" : "form" + } ], + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__get_200_response" } }, - "text/csv": { - "schema": { - "$ref": "#/components/schemas/Document" + "text/csv" : { + "schema" : { + "$ref" : "#/components/schemas/Document" } }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/Document" + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/Document" } } + }, + "description" : "The document has been succesfully found and its JSON form returned in the response content.", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModified" + } } }, - "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" + "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 JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" } } - } + }, + "description" : "The collection or document specified was not found." }, - "406": { - "description": "The requested content type (in `Accept` header) is not supported.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_406" + "406" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_406_response" } } - } + }, + "description" : "The requested content type (in `Accept` header) is not supported." }, - "410": { - "description": "The requested document has already been deleted.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_410" + "410" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__get_410_response" } } - } + }, + "description" : "The requested document has already been deleted." } }, - "security": [ - { - "jwtoken": [] - } - ] - }, - "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 200 HTTP status code will be returned.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code 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": "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 + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "READ: Retrieves a single document from the collection", + "tags" : [ "generic" ] + }, + "patch" : { + "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 200 HTTP status code will be returned.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code 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" : [ { + "description" : "Collection to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "collection", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramCollection" + }, + "style" : "simple" + }, { + "description" : "Identifier of the document to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "identifier", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramIdentifier" + }, + "style" : "simple" + }, { + "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
", + "explode" : false, + "in" : "header", + "name" : "If-Unmodified-Since", + "required" : false, + "schema" : { + "type" : "string" + }, + "style" : "simple" + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentToPost" + } + } + }, + "description" : "JSON of new version of document (`identifier` in JSON is ignored if present)", + "required" : true }, - "responses": { - "200": { - "description": "The request was successfully processed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_3" + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__put_200_response" } } - } - }, - "201": { - "description": "Successfully created a new document in collection", - "headers": { - "Last-Modified": { - "$ref": "#/components/schemas/headerLastModified" - } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_201" - } - } - } + "description" : "The request was successfully processed" }, - "400": { - "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_400" + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_400_response" } } - } + }, + "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 JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" } } - } + }, + "description" : "The collection or document specified was not found." }, - "410": { - "description": "The requested document has already been deleted.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_410" + "410" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__get_410_response" } } - } + }, + "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).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_412" + "412" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__put_412_response" } } - } + }, + "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`).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_422" + "422" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_422_response" } } - } + }, + "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": [ - { - "jwtoken": [] - } - ] - }, - "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": "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": { - "200": { - "description": "The request was successfully processed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_3" - } - } - } - }, - "401": { - "description": "The request was not successfully authenticated using JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" - } - } - } - }, - "403": { - "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" - } - } - } - }, - "404": { - "description": "The collection or document specified was not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "PATCH: Partially updates document in the collection", + "tags" : [ "generic" ] + }, + "put" : { + "description" : "Normally the document with the matching `identifier` will be replaced in the collection by the whole JSON request body and 200 HTTP status code will be returned.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code 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" : [ { + "description" : "Collection to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "collection", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramCollection" + }, + "style" : "simple" + }, { + "description" : "Identifier of the document to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "identifier", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramIdentifier" + }, + "style" : "simple" + }, { + "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
", + "explode" : false, + "in" : "header", + "name" : "If-Unmodified-Since", + "required" : false, + "schema" : { + "type" : "string" + }, + "style" : "simple" + } ], + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentToPost" + } + } + }, + "description" : "JSON of new version of document (`identifier` in JSON is ignored if present)", + "required" : true + }, + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__put_200_response" } } - } + }, + "description" : "The request was successfully processed" }, - "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`).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_422" + "201" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_201_response" } } - } - } - }, - "security": [ - { - "jwtoken": [] - } - ] - }, - "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 200 HTTP status code will be returned.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code 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": "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": { - "200": { - "description": "The request was successfully processed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_3" - } + }, + "description" : "Successfully created a new document in collection", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModified" } } }, - "400": { - "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_400" + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_400_response" } } - } + }, + "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 JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" } } - } + }, + "description" : "The collection or document specified was not found." }, - "410": { - "description": "The requested document has already been deleted.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_410" + "412" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__put_412_response" } } - } + }, + "description" : "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header)." }, - "412": { - "description": "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_412" + "410" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__get_410_response" } } - } + }, + "description" : "The requested document has already been deleted." }, - "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`).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_422" + "422" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_422_response" } } - } + }, + "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": [ - { - "jwtoken": [] - } - ] + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "UPDATE: Updates a document in the collection", + "tags" : [ "generic" ] } }, - "/{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\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": "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" - } + "/{collection}/history" : { + "get" : { + "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\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" : [ { + "description" : "Collection to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "collection", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramCollection" + }, + "style" : "simple" + }, { + "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
", + "explode" : false, + "in" : "header", + "name" : "Last-Modified", + "required" : true, + "schema" : { + "type" : "string" + }, + "style" : "simple" + }, { + "description" : "Maximum number of documents to get in result array", + "explode" : true, + "in" : "query", + "name" : "limit", + "required" : false, + "schema" : { + "example" : 100, + "minimum" : 1, + "type" : "integer" + }, + "style" : "form" + }, { + "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", + "examples" : { + "all" : { + "summary" : "All fields will be returned (default behaviour)", + "value" : "_all" }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200" + "customSet" : { + "summary" : "Only fields date and insulin will be returned", + "value" : "date,insulin" + } + }, + "explode" : true, + "in" : "query", + "name" : "fields", + "required" : false, + "schema" : { + "default" : "_all", + "type" : "string" + }, + "style" : "form" + } ], + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_200_response" } }, - "text/csv": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" + "text/csv" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" } }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" } } + }, + "description" : "Changed documents since specified timestamp", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModifiedMaximum" + }, + "ETag" : { + "$ref" : "#/components/schemas/headerEtagLastModifiedMaximum" + } } }, - "400": { - "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_400" + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_400_response" } } - } + }, + "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 JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" } } - } + }, + "description" : "The collection or document specified was not found." }, - "406": { - "description": "The requested content type (in `Accept` header) is not supported.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_406" + "406" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_406_response" } } - } + }, + "description" : "The requested content type (in `Accept` header) is not supported." } }, - "security": [ - { - "jwtoken": [] - } - ] + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "HISTORY: Retrieves incremental changes since timestamp", + "tags" : [ "generic" ] } }, - "/{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": "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" - } + "/{collection}/history/{lastModified}" : { + "get" : { + "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" : [ { + "description" : "Collection to which the operation is targeted", + "explode" : false, + "in" : "path", + "name" : "collection", + "required" : true, + "schema" : { + "$ref" : "#/components/schemas/paramCollection" + }, + "style" : "simple" + }, { + "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).", + "explode" : false, + "in" : "path", + "name" : "lastModified", + "required" : true, + "schema" : { + "format" : "int64", + "type" : "integer" + }, + "style" : "simple" + }, { + "description" : "Maximum number of documents to get in result array", + "explode" : true, + "in" : "query", + "name" : "limit", + "required" : false, + "schema" : { + "example" : 100, + "minimum" : 1, + "type" : "integer" + }, + "style" : "form" + }, { + "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", + "examples" : { + "all" : { + "summary" : "All fields will be returned (default behaviour)", + "value" : "_all" }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200" + "customSet" : { + "summary" : "Only fields date and insulin will be returned", + "value" : "date,insulin" + } + }, + "explode" : true, + "in" : "query", + "name" : "fields", + "required" : false, + "schema" : { + "default" : "_all", + "type" : "string" + }, + "style" : "form" + } ], + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_200_response" } }, - "text/csv": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" + "text/csv" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" } }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" } } + }, + "description" : "Changed documents since specified timestamp", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModifiedMaximum" + }, + "ETag" : { + "$ref" : "#/components/schemas/headerEtagLastModifiedMaximum" + } } }, - "400": { - "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_400" + "400" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_400_response" } } - } + }, + "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 JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" + "404" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" } } - } + }, + "description" : "The collection or document specified was not found." }, - "406": { - "description": "The requested content type (in `Accept` header) is not supported.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_406" + "406" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_406_response" } } - } + }, + "description" : "The requested content type (in `Accept` header) is not supported." } }, - "security": [ - { - "jwtoken": [] - } - ] + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "HISTORY: Retrieves incremental changes since timestamp", + "tags" : [ "generic" ] } }, - "/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" + "/version" : { + "get" : { + "description" : "No authentication is needed for this commnad (it is public)", + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Version" } } - } + }, + "description" : "Successful response" } - } + }, + "summary" : "VERSION: Returns actual version information", + "tags" : [ "other" ] } }, - "/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" + "/status" : { + "get" : { + "description" : "This operation requires authorization in contrast with VERSION operation.", + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Status" } } - } + }, + "description" : "Successful response" }, - "401": { - "description": "The request was not successfully authenticated using JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "description" : "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." } }, - "security": [ - { - "jwtoken": [] - } - ] + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "STATUS: Returns actual version information and all permissions granted for API", + "tags" : [ "other" ] } }, - "/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", - "responses": { - "200": { - "description": "Successful operation returning the timestamps", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_4" + "/lastModified" : { + "get" : { + "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", + "responses" : { + "200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/LAST_MODIFIED_200_response" } } - } + }, + "description" : "Successful operation returning the timestamps" }, - "401": { - "description": "The request was not successfully authenticated using JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "401" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - } + }, + "description" : "The request was not successfully authenticated using JWT, 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.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" + "403" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" } } - } + }, + "description" : "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." } }, - "security": [ - { - "jwtoken": [] - } - ] + "security" : [ { + "jwtoken" : [ ] + } ], + "summary" : "LAST MODIFIED: Retrieves timestamp of the last modification of every collection", + "tags" : [ "other" ] } } }, - "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" - }, - "identifierField": { - "type": "string", - "description": "Identifier of created or modified document", - "example": "53409478-105f-11e9-ab14-d663bd873d93" - }, - "lastModifiedField": { - "type": "integer", - "description": "Timestamp of the last document modification on the server, formatted as\nUnix epoch in milliseconds (1525383610088)", - "format": "int64", - "example": 1525383610088 - }, - "statusField": { - "type": "integer", - "description": "HTTP response status code. The status appears also in response body's field for those clients that are unable to process standard HTTP status code.", - "example": 200 - }, - "isDeduplicationField": { - "type": "boolean", - "description": "Flag whether the operation found a duplicate document (to update)", - "example": true - }, - "deduplicatedIdentifierField": { - "type": "string", - "description": "The original document that has been marked as a duplicate document and which has been updated", - "example": "abc09478-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 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 - } + "components" : { + "parameters" : { + "limitParam" : { + "description" : "Maximum number of documents to get in result array", + "explode" : true, + "in" : "query", + "name" : "limit", + "required" : false, + "schema" : { + "example" : 100, + "minimum" : 1, + "type" : "integer" + }, + "style" : "form" + }, + "skipParam" : { + "description" : "Number of documents to skip from collection query before loading them into result array (used for pagination)", + "explode" : true, + "in" : "query", + "name" : "skip", + "required" : false, + "schema" : { + "default" : 0, + "example" : 0, + "minimum" : 0, + "type" : "integer" + }, + "style" : "form" + }, + "sortParam" : { + "description" : "Field name by which the sorting of documents is performed. This parameter cannot be combined with `sort$desc` parameter.", + "explode" : true, + "in" : "query", + "name" : "sort", + "required" : false, + "schema" : { + "type" : "string" }, - "description": "Shared base for all documents" + "style" : "form" + }, + "sortDescParam" : { + "description" : "Field name by which the descending (reverse) sorting of documents is performed. This parameter cannot be combined with `sort` parameter.", + "explode" : true, + "in" : "query", + "name" : "sort$desc", + "required" : false, + "schema" : { + "type" : "string" + }, + "style" : "form" + }, + "permanentParam" : { + "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.", + "explode" : true, + "in" : "query", + "name" : "permanent", + "required" : false, + "schema" : { + "type" : "boolean" + }, + "style" : "form" }, - "DeviceStatus": { - "description": "State of physical device, which is a technical part of the whole T1D compensation system", - "allOf": [ - { - "$ref": "#/components/schemas/DocumentBase" + "fieldsParam" : { + "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", + "examples" : { + "all" : { + "summary" : "All fields will be returned (default behaviour)", + "value" : "_all" }, - { - "type": "object", - "properties": { - "some_property": { - "type": "string", - "description": "..." - } - } + "customSet" : { + "summary" : "Only fields date and insulin will be returned", + "value" : "date,insulin" } - ] - }, - "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" - } - } + }, + "explode" : true, + "in" : "query", + "name" : "fields", + "required" : false, + "schema" : { + "default" : "_all", + "type" : "string" + }, + "style" : "form" + }, + "filterParams" : { + "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`).", + "explode" : false, + "in" : "query", + "name" : "filter_parameters", + "required" : false, + "schema" : { + "items" : { + "type" : "string" + }, + "type" : "array" + }, + "style" : "spaceDelimited" + }, + "lastModifiedRequiredHeader" : { + "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
", + "explode" : false, + "in" : "header", + "name" : "Last-Modified", + "required" : true, + "schema" : { + "type" : "string" + }, + "style" : "simple" + }, + "ifModifiedSinceHeader" : { + "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
", + "explode" : false, + "in" : "header", + "name" : "If-Modified-Since", + "required" : false, + "schema" : { + "type" : "string" + }, + "style" : "simple" + }, + "ifUnmodifiedSinceHeader" : { + "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
", + "explode" : false, + "in" : "header", + "name" : "If-Unmodified-Since", + "required" : false, + "schema" : { + "type" : "string" + }, + "style" : "simple" + } + }, + "responses" : { + "200Ok" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__put_200_response" } } - ] + }, + "description" : "The request was successfully processed" }, - "Profile": { - "description": "Parameters describing body functioning relative to T1D + compensation parameters", - "allOf": [ - { - "$ref": "#/components/schemas/DocumentBase" - }, - { - "type": "object", - "properties": { - "some_property": { - "type": "string", - "description": "..." - } + "200Deduplication" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_200_response" } } - ] - }, - "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" + }, + "description" : "Successfully updated a duplicate document in the collection", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModified" }, - { - "type": "object", - "properties": { - "some_property": { - "type": "string", - "description": "..." - } - } + "Location" : { + "$ref" : "#/components/schemas/headerLocation" } - ] - }, - "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." - } + } + }, + "201Created" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_201_response" } } - ] - }, - "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" + "description" : "Successfully created a new document in collection", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModified" } - ] - }, - "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" + "201CreatedLocation" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_201_response" + } + } }, - "oneOf": [ - { - "$ref": "#/components/schemas/DeviceStatusArray" - }, - { - "$ref": "#/components/schemas/EntryArray" - }, - { - "$ref": "#/components/schemas/FoodArray" - }, - { - "$ref": "#/components/schemas/ProfileArray" + "description" : "Successfully created a new document in collection", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModified" }, - { - "$ref": "#/components/schemas/SettingsArray" - }, - { - "$ref": "#/components/schemas/TreatmentArray" + "Location" : { + "$ref" : "#/components/schemas/headerLocation" } - ] + } }, - "Version": { - "type": "object", - "properties": { - "status": { - "$ref": "#/components/schemas/statusField" - }, - "result": { - "$ref": "#/components/schemas/VersionResult" - } - }, - "description": "Information about versions" - }, - "VersionResult": { - "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": { - "$ref": "#/components/schemas/VersionResult_storage" + "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" } } }, - "Status": { - "properties": { - "status": { - "$ref": "#/components/schemas/statusField" - }, - "result": { - "$ref": "#/components/schemas/StatusResult" + "400BadRequest" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_400_response" + } } }, - "description": "Information about versions and API permissions" + "description" : "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present." }, - "StatusResult": { - "allOf": [ - { - "$ref": "#/components/schemas/VersionResult" - }, - { - "type": "object", - "properties": { - "apiPermissions": { - "$ref": "#/components/schemas/StatusResult_apiPermissions" - } + "401Unauthorized" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_401_response" } } - ] - }, - "LastModifiedResult": { - "properties": { - "srvDate": { - "type": "integer", - "description": "Actual storage server date (Unix epoch in ms).", - "format": "int64", - "example": 1556260878776 - }, - "collections": { - "$ref": "#/components/schemas/LastModifiedResult_collections" - } }, - "description": "Result of LAST MODIFIED operation" + "description" : "The request was not successfully authenticated using JWT, so that the request cannot continue due to the security policy." }, - "inline_response_200": { - "properties": { - "status": { - "type": "integer", - "example": 200 - }, - "result": { - "$ref": "#/components/schemas/DocumentArray" + "403Forbidden" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_403_response" + } } - } + }, + "description" : "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." }, - "inline_response_400": { - "properties": { - "status": { - "type": "integer", - "example": 400 + "404NotFound" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_404_response" + } } - } + }, + "description" : "The collection or document specified was not found." }, - "inline_response_401": { - "properties": { - "status": { - "type": "integer", - "example": 401 + "406NotAcceptable" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_406_response" + } } - } + }, + "description" : "The requested content type (in `Accept` header) is not supported." }, - "inline_response_403": { - "properties": { - "status": { - "type": "integer", - "example": 403 + "412PreconditionFailed" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__put_412_response" + } } - } + }, + "description" : "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header)." }, - "inline_response_404": { - "properties": { - "status": { - "type": "integer", - "example": 404 + "410Gone" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__get_410_response" + } } - } + }, + "description" : "The requested document has already been deleted." }, - "inline_response_406": { - "properties": { - "status": { - "type": "integer", - "example": 406 + "422UnprocessableEntity" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection__post_422_response" + } } - } + }, + "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`)." }, - "inline_response_200_1": { - "properties": { - "status": { - "type": "integer", - "example": 200 - }, - "identifier": { - "$ref": "#/components/schemas/identifierField" + "search200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_200_response" + } }, - "isDeduplication": { - "$ref": "#/components/schemas/isDeduplicationField" + "text/csv" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" + } }, - "deduplicatedIdentifier": { - "$ref": "#/components/schemas/deduplicatedIdentifierField" + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" + } } - } + }, + "description" : "Successful operation returning array of documents matching the filtering criteria" }, - "inline_response_201": { - "properties": { - "status": { - "type": "integer", - "example": 201 + "read200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/__collection___identifier__get_200_response" + } }, - "identifier": { - "$ref": "#/components/schemas/identifierField" + "text/csv" : { + "schema" : { + "$ref" : "#/components/schemas/Document" + } }, - "lastModified": { - "$ref": "#/components/schemas/lastModifiedField" + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/Document" + } } - } - }, - "inline_response_422": { - "properties": { - "status": { - "type": "integer", - "example": 422 + }, + "description" : "The document has been succesfully found and its JSON form returned in the response content.", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModified" } } }, - "inline_response_200_2": { - "properties": { - "status": { - "type": "integer", - "example": 200 + "history200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/SEARCH_200_response" + } }, - "result": { - "$ref": "#/components/schemas/Document" - } - } - }, - "inline_response_410": { - "properties": { - "status": { - "type": "integer", - "example": 410 - } - } - }, - "inline_response_200_3": { - "properties": { - "status": { - "type": "integer", - "example": 200 - } - } - }, - "inline_response_412": { - "properties": { - "status": { - "type": "integer", - "example": 412 - } - } - }, - "inline_response_200_4": { - "properties": { - "status": { - "type": "integer", - "example": 200 + "text/csv" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" + } }, - "result": { - "$ref": "#/components/schemas/LastModifiedResult" - } - } - }, - "VersionResult_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" + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/DocumentArray" + } } - } - }, - "StatusResult_apiPermissions": { - "type": "object", - "properties": { - "devicestatus": { - "type": "string", - "example": "crud" - }, - "entries": { - "type": "string", - "example": "r" - }, - "food": { - "type": "string", - "example": "crud" - }, - "profile": { - "type": "string", - "example": "r" + }, + "description" : "Changed documents since specified timestamp", + "headers" : { + "Last-Modified" : { + "$ref" : "#/components/schemas/headerLastModifiedMaximum" }, - "treatments": { - "type": "string", - "example": "crud" + "ETag" : { + "$ref" : "#/components/schemas/headerEtagLastModifiedMaximum" } } }, - "LastModifiedResult_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 + "lastModified200" : { + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/LAST_MODIFIED_200_response" + } } }, - "description": "Collections which the user have read access to." + "description" : "Successful operation returning the timestamps" } }, - "responses": { - "200Ok": { - "description": "The request was successfully processed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_3" - } + "schemas" : { + "headerLocation" : { + "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", + "type" : "string" + }, + "headerLastModified" : { + "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'", + "type" : "string" + }, + "headerLastModifiedMaximum" : { + "description" : "The latest (maximum) `srvModified` field of all returning documents, formatted as\n', :: GMT'.\nExample='Wed, 17 Oct 2018 05:13:00 GMT'", + "type" : "string" + }, + "headerEtagLastModifiedMaximum" : { + "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\"'", + "type" : "string" + }, + "paramCollection" : { + "enum" : [ "devicestatus", "entries", "food", "profile", "settings", "treatments" ], + "example" : "treatments", + "type" : "string" + }, + "paramIdentifier" : { + "example" : "53409478-105f-11e9-ab14-d663bd873d93", + "type" : "string" + }, + "identifierField" : { + "description" : "Identifier of created or modified document", + "example" : "53409478-105f-11e9-ab14-d663bd873d93", + "type" : "string" + }, + "lastModifiedField" : { + "description" : "Timestamp of the last document modification on the server, formatted as\nUnix epoch in milliseconds (1525383610088)", + "example" : 1525383610088, + "format" : "int64", + "type" : "integer" + }, + "statusField" : { + "description" : "HTTP response status code. The status appears also in response body's field for those clients that are unable to process standard HTTP status code.", + "example" : 200, + "type" : "integer" + }, + "isDeduplicationField" : { + "description" : "Flag whether the operation found a duplicate document (to update)", + "example" : true, + "type" : "boolean" + }, + "deduplicatedIdentifierField" : { + "description" : "The original document that has been marked as a duplicate document and which has been updated", + "example" : "abc09478-105f-11e9-ab14-d663bd873d93", + "type" : "string" + }, + "DocumentBase" : { + "description" : "Shared base for all documents", + "properties" : { + "identifier" : { + "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", + "type" : "string" + }, + "date" : { + "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)", + "example" : 1525383610088, + "format" : "int64", + "type" : "integer" + }, + "utcOffset" : { + "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, + "type" : "integer" + }, + "app" : { + "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", + "type" : "string" + }, + "device" : { + "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", + "type" : "string" + }, + "_id" : { + "description" : "Internally assigned database id. This field is for internal server purposes only, clients communicate with API by using identifier field.", + "example" : "58e9dfbc166d88cc18683aac", + "type" : "string" + }, + "srvCreated" : { + "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)", + "example" : 1525383610088, + "format" : "int64", + "type" : "integer" + }, + "subject" : { + "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 JWT.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example" : "uploader", + "type" : "string" + }, + "srvModified" : { + "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)", + "example" : 1525383610088, + "format" : "int64", + "type" : "integer" + }, + "modifiedBy" : { + "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", + "type" : "string" + }, + "isValid" : { + "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, + "type" : "boolean" + }, + "isReadOnly" : { + "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, + "type" : "boolean" } + }, + "required" : [ "app", "date" ] + }, + "DeviceStatus" : { + "allOf" : [ { + "$ref" : "#/components/schemas/DocumentBase" + }, { + "properties" : { + "some_property" : { + "description" : "...", + "type" : "string" + } + }, + "type" : "object" + } ], + "description" : "State of physical device, which is a technical part of the whole T1D compensation system" + }, + "Entry" : { + "allOf" : [ { + "$ref" : "#/components/schemas/DocumentBase" + }, { + "properties" : { + "type" : { + "description" : "sgv, mbg, cal, etc", + "type" : "string" + }, + "sgv" : { + "description" : "The glucose reading. (only available for sgv types)", + "type" : "number" + }, + "direction" : { + "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", + "type" : "string" + }, + "noise" : { + "description" : "Noise level at time of reading. (only available for sgv types)", + "type" : "number" + }, + "filtered" : { + "description" : "The raw filtered value directly from CGM transmitter. (only available for sgv types)", + "type" : "number" + }, + "unfiltered" : { + "description" : "The raw unfiltered value directly from CGM transmitter. (only available for sgv types)", + "type" : "number" + }, + "rssi" : { + "description" : "The signal strength from CGM transmitter. (only available for sgv types)", + "type" : "number" + }, + "units" : { + "description" : "The units for the glucose value, mg/dl or mmol/l. It is strongly recommended to fill in this field.", + "example" : "\"mg\", \"mmol\"", + "type" : "string" + } + }, + "type" : "object" + } ], + "description" : "Blood glucose measurements and CGM calibrations" + }, + "Food" : { + "allOf" : [ { + "$ref" : "#/components/schemas/DocumentBase" + }, { + "properties" : { + "food" : { + "description" : "food, quickpick", + "type" : "string" + }, + "category" : { + "description" : "Name for a group of related records", + "type" : "string" + }, + "subcategory" : { + "description" : "Name for a second level of groupping", + "type" : "string" + }, + "name" : { + "description" : "Name of the food described", + "type" : "string" + }, + "portion" : { + "description" : "Number of units (e.g. grams) of the whole portion described", + "type" : "number" + }, + "unit" : { + "description" : "Unit for the portion", + "example" : "\"g\", \"ml\", \"oz\"", + "type" : "string" + }, + "carbs" : { + "description" : "Amount of carbs in the portion in grams", + "type" : "number" + }, + "fat" : { + "description" : "Amount of fat in the portion in grams", + "type" : "number" + }, + "protein" : { + "description" : "Amount of proteins in the portion in grams", + "type" : "number" + }, + "energy" : { + "description" : "Amount of energy in the portion in kJ", + "type" : "number" + }, + "gi" : { + "description" : "Glycemic index (1=low, 2=medium, 3=high)", + "type" : "number" + }, + "hideafteruse" : { + "description" : "Flag used for quickpick", + "type" : "boolean" + }, + "hidden" : { + "description" : "Flag used for quickpick", + "type" : "boolean" + }, + "position" : { + "description" : "Ordering field for quickpick", + "type" : "number" + }, + "portions" : { + "description" : "component multiplier if defined inside quickpick compound", + "type" : "number" + }, + "foods" : { + "description" : "Neighbour documents (from food collection) that together make a quickpick compound", + "items" : { + "$ref" : "#/components/schemas/Food" + }, + "type" : "array" + } + }, + "type" : "object" + } ], + "description" : "Nutritional values of food" + }, + "Profile" : { + "allOf" : [ { + "$ref" : "#/components/schemas/DocumentBase" + }, { + "properties" : { + "some_property" : { + "description" : "...", + "type" : "string" + } + }, + "type" : "object" + } ], + "description" : "Parameters describing body functioning relative to T1D + compensation parameters" + }, + "Settings" : { + "allOf" : [ { + "$ref" : "#/components/schemas/DocumentBase" + }, { + "properties" : { + "some_property" : { + "description" : "...", + "type" : "string" + } + }, + "type" : "object" + } ], + "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." + }, + "Treatment" : { + "allOf" : [ { + "$ref" : "#/components/schemas/DocumentBase" + }, { + "properties" : { + "eventType" : { + "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\"", + "type" : "string" + }, + "glucose" : { + "description" : "Current glucose.", + "type" : "string" + }, + "glucoseType" : { + "description" : "Method used to obtain glucose, Finger or Sensor.", + "example" : "\"Sensor\", \"Finger\", \"Manual\"", + "type" : "string" + }, + "units" : { + "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\"", + "type" : "string" + }, + "carbs" : { + "description" : "Amount of carbs given.", + "type" : "number" + }, + "protein" : { + "description" : "Amount of protein given.", + "type" : "number" + }, + "fat" : { + "description" : "Amount of fat given.", + "type" : "number" + }, + "insulin" : { + "description" : "Amount of insulin, if any.", + "type" : "number" + }, + "duration" : { + "description" : "Duration in minutes.", + "type" : "number" + }, + "preBolus" : { + "description" : "How many minutes the bolus was given before the meal started.", + "type" : "number" + }, + "splitNow" : { + "description" : "Immediate part of combo bolus (in percent).", + "type" : "number" + }, + "splitExt" : { + "description" : "Extended part of combo bolus (in percent).", + "type" : "number" + }, + "percent" : { + "description" : "Eventual basal change in percent.", + "type" : "number" + }, + "absolute" : { + "description" : "Eventual basal change in absolute value (insulin units per hour).", + "type" : "number" + }, + "targetTop" : { + "description" : "Top limit of temporary target.", + "type" : "number" + }, + "targetBottom" : { + "description" : "Bottom limit of temporary target.", + "type" : "number" + }, + "profile" : { + "description" : "Name of the profile to which the pump has been switched.", + "type" : "string" + }, + "reason" : { + "description" : "For example the reason why the profile has been switched or why the temporary target has been set.", + "type" : "string" + }, + "notes" : { + "description" : "Description/notes of treatment.", + "type" : "string" + }, + "enteredBy" : { + "description" : "Who entered the treatment.", + "type" : "string" + } + }, + "type" : "object" + } ], + "description" : "T1D compensation action" + }, + "DocumentToPost" : { + "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" + } ], + "type" : "object" + }, + "Document" : { + "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" + }, + "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" + } ], + "type" : "object", + "xml" : { + "name" : "item" } }, - "200Deduplication": { - "description": "Successfully updated a duplicate document in the collection", - "headers": { - "Last-Modified": { - "$ref": "#/components/schemas/headerLastModified" - }, - "Location": { - "$ref": "#/components/schemas/headerLocation" - } + "DeviceStatusArray" : { + "description" : "Array of documents", + "items" : { + "$ref" : "#/components/schemas/DeviceStatus" }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_1" - } - } - } + "type" : "array" }, - "201Created": { - "description": "Successfully created a new document in collection", - "headers": { - "Last-Modified": { - "$ref": "#/components/schemas/headerLastModified" - } + "EntryArray" : { + "description" : "Array of documents", + "items" : { + "$ref" : "#/components/schemas/Entry" }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_201" - } - } + "type" : "array" + }, + "FoodArray" : { + "description" : "Array of documents", + "items" : { + "$ref" : "#/components/schemas/Food" + }, + "type" : "array" + }, + "ProfileArray" : { + "description" : "Array of documents", + "items" : { + "$ref" : "#/components/schemas/Profile" + }, + "type" : "array" + }, + "SettingsArray" : { + "description" : "Array of settings", + "items" : { + "$ref" : "#/components/schemas/Settings" + }, + "type" : "array" + }, + "TreatmentArray" : { + "description" : "Array of documents", + "items" : { + "$ref" : "#/components/schemas/Treatment" + }, + "type" : "array" + }, + "DocumentArray" : { + "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" + } ], + "type" : "object", + "xml" : { + "name" : "items" } }, - "201CreatedLocation": { - "description": "Successfully created a new document in collection", - "headers": { - "Last-Modified": { - "$ref": "#/components/schemas/headerLastModified" + "Version" : { + "description" : "Information about versions", + "properties" : { + "status" : { + "$ref" : "#/components/schemas/statusField" }, - "Location": { - "$ref": "#/components/schemas/headerLocation" + "result" : { + "$ref" : "#/components/schemas/VersionResult" } }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_201" - } - } - } + "type" : "object" }, - "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" + "VersionResult" : { + "properties" : { + "version" : { + "description" : "The whole Nightscout instance version", + "example" : "0.10.2-release-20171201", + "type" : "string" + }, + "apiVersion" : { + "description" : "API v3 subsystem version", + "example" : "3.0.0", + "type" : "string" + }, + "srvDate" : { + "description" : "Actual server date and time in UNIX epoch format", + "example" : 1532936118000, + "type" : "number" + }, + "storage" : { + "$ref" : "#/components/schemas/VersionResult_storage" } - } + }, + "type" : "object" }, - "400BadRequest": { - "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_400" - } + "Status" : { + "description" : "Information about versions and API permissions", + "properties" : { + "status" : { + "$ref" : "#/components/schemas/statusField" + }, + "result" : { + "$ref" : "#/components/schemas/StatusResult" } } }, - "401Unauthorized": { - "description": "The request was not successfully authenticated using JWT, so that the request cannot continue due to the security policy.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_401" + "StatusResult" : { + "allOf" : [ { + "$ref" : "#/components/schemas/VersionResult" + }, { + "properties" : { + "apiPermissions" : { + "$ref" : "#/components/schemas/StatusResult_allOf_apiPermissions" } + }, + "type" : "object" + } ] + }, + "LastModifiedResult" : { + "description" : "Result of LAST MODIFIED operation", + "properties" : { + "srvDate" : { + "description" : "Actual storage server date (Unix epoch in ms).", + "example" : 1556260878776, + "format" : "int64", + "type" : "integer" + }, + "collections" : { + "$ref" : "#/components/schemas/LastModifiedResult_collections" } } }, - "403Forbidden": { - "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_403" - } + "SEARCH_200_response" : { + "properties" : { + "status" : { + "example" : 200, + "type" : "integer" + }, + "result" : { + "$ref" : "#/components/schemas/DocumentArray" } } }, - "404NotFound": { - "description": "The collection or document specified was not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_404" - } + "SEARCH_400_response" : { + "properties" : { + "status" : { + "example" : 400, + "type" : "integer" } } }, - "406NotAcceptable": { - "description": "The requested content type (in `Accept` header) is not supported.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_406" - } + "SEARCH_401_response" : { + "properties" : { + "status" : { + "example" : 401, + "type" : "integer" } } }, - "412PreconditionFailed": { - "description": "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_412" - } + "SEARCH_403_response" : { + "properties" : { + "status" : { + "example" : 403, + "type" : "integer" } } }, - "410Gone": { - "description": "The requested document has already been deleted.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_410" - } + "SEARCH_404_response" : { + "properties" : { + "status" : { + "example" : 404, + "type" : "integer" } } }, - "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`).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_422" - } + "SEARCH_406_response" : { + "properties" : { + "status" : { + "example" : 406, + "type" : "integer" } } }, - "search200": { - "description": "Successful operation returning array of documents matching the filtering criteria", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200" - } + "__collection__post_200_response" : { + "properties" : { + "status" : { + "example" : 200, + "type" : "integer" }, - "text/csv": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" - } + "identifier" : { + "$ref" : "#/components/schemas/identifierField" }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" - } + "isDeduplication" : { + "$ref" : "#/components/schemas/isDeduplicationField" + }, + "deduplicatedIdentifier" : { + "$ref" : "#/components/schemas/deduplicatedIdentifierField" } } }, - "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/inline_response_200_2" - } + "__collection__post_201_response" : { + "properties" : { + "status" : { + "example" : 201, + "type" : "integer" }, - "text/csv": { - "schema": { - "$ref": "#/components/schemas/Document" - } + "identifier" : { + "$ref" : "#/components/schemas/identifierField" }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/Document" - } + "lastModified" : { + "$ref" : "#/components/schemas/lastModifiedField" } } }, - "history200": { - "description": "Changed documents since specified timestamp", - "headers": { - "Last-Modified": { - "$ref": "#/components/schemas/headerLastModifiedMaximum" - }, - "ETag": { - "$ref": "#/components/schemas/headerEtagLastModifiedMaximum" + "__collection__post_422_response" : { + "properties" : { + "status" : { + "example" : 422, + "type" : "integer" } - }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200" - } - }, - "text/csv": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" - } + } + }, + "__collection___identifier__get_200_response" : { + "properties" : { + "status" : { + "example" : 200, + "type" : "integer" }, - "application/xml": { - "schema": { - "$ref": "#/components/schemas/DocumentArray" - } + "result" : { + "$ref" : "#/components/schemas/Document" } } }, - "lastModified200": { - "description": "Successful operation returning the timestamps", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/inline_response_200_4" - } + "__collection___identifier__get_410_response" : { + "properties" : { + "status" : { + "example" : 410, + "type" : "integer" } } - } - }, - "parameters": { - "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 + "__collection___identifier__put_200_response" : { + "properties" : { + "status" : { + "example" : 200, + "type" : "integer" + } } }, - "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" + "__collection___identifier__put_412_response" : { + "properties" : { + "status" : { + "example" : 412, + "type" : "integer" + } } }, - "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" + "LAST_MODIFIED_200_response" : { + "properties" : { + "status" : { + "example" : 200, + "type" : "integer" + }, + "result" : { + "$ref" : "#/components/schemas/LastModifiedResult" + } } }, - "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" - } + "VersionResult_storage" : { + "properties" : { + "type" : { + "description" : "Type of storage engine used", + "example" : "mongodb", + "type" : "string" + }, + "version" : { + "description" : "Version of the storage engine", + "example" : "4.0.6", + "type" : "string" + } + }, + "type" : "object" }, - "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" + "StatusResult_allOf_apiPermissions" : { + "properties" : { + "devicestatus" : { + "example" : "crud", + "type" : "string" + }, + "entries" : { + "example" : "r", + "type" : "string" + }, + "food" : { + "example" : "crud", + "type" : "string" + }, + "profile" : { + "example" : "r", + "type" : "string" + }, + "treatments" : { + "example" : "crud", + "type" : "string" + } }, - "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" + "type" : "object" + }, + "LastModifiedResult_collections" : { + "description" : "Collections which the user have read access to.", + "properties" : { + "devicestatus" : { + "description" : "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.", + "example" : 1556260760974, + "format" : "int64", + "type" : "integer" + }, + "treatments" : { + "description" : "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.", + "example" : 1553374184169, + "format" : "int64", + "type" : "integer" + }, + "entries" : { + "description" : "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.", + "example" : 1556260758768, + "format" : "int64", + "type" : "integer" + }, + "profile" : { + "description" : "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.", + "example" : 1548524042744, + "format" : "int64", + "type" : "integer" } - } - }, - "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" - } + }, + "type" : "object" } }, - "securitySchemes": { - "jwtoken": { - "type": "http", - "description": "Use this if you know the temporary json webtoken.", - "scheme": "bearer", - "bearerFormat": "JWT" + "securitySchemes" : { + "jwtoken" : { + "bearerFormat" : "JWT", + "description" : "Use this if you know the temporary json webtoken.", + "scheme" : "bearer", + "type" : "http" } } } -} +} \ No newline at end of file diff --git a/lib/api3/swagger.yaml b/lib/api3/swagger.yaml index 332b00e86bf..5e3c11c2386 100644 --- a/lib/api3/swagger.yaml +++ b/lib/api3/swagger.yaml @@ -650,7 +650,10 @@ components: in: query name: filter_parameters schema: - type: string + type: array + items: + type: string + style: spaceDelimited description: Any number of filtering operators. diff --git a/tests/api3.search.test.js b/tests/api3.search.test.js index aeafc84630c..9d2fedfa827 100644 --- a/tests/api3.search.test.js +++ b/tests/api3.search.test.js @@ -204,6 +204,114 @@ describe('API3 SEARCH', function() { }); + it('should filter entries', async () => { + let res = await self.instance.get(`${self.url}?sgv$eq=${testConst.SAMPLE_ENTRIES[4].sgv}`, self.jwt.read) + .expect(200); + + res.body.status.should.equal(200); + const results = res.body.result; + const length = results.length; + length.should.be.aboveOrEqual(1); + + for (let i in results) { + results[i].sgv.should.equal(testConst.SAMPLE_ENTRIES[4].sgv); + } + }); + + + it('should filter entries by multiple parameters', async () => { + let res = await self.instance.get(`${self.url}?date$gt=${testConst.SAMPLE_ENTRIES[2].date}&sgv$lte=179`, self.jwt.read) + .expect(200); + + res.body.status.should.equal(200); + const results = res.body.result; + const length = results.length; + length.should.be.aboveOrEqual(5); + + for (let i in results) { + results[i].date.should.be.aboveOrEqual(testConst.SAMPLE_ENTRIES[2].date); + results[i].sgv.should.be.belowOrEqual(179); + } + }); + + + it('should filter entries by ISO8601 date', async () => { + let res = await self.instance.get(`${self.url}?date$eq=2017-04-09T06:18:50`, self.jwt.read) + .expect(200); + + res.body.status.should.equal(200); + const results = res.body.result; + const length = results.length; + length.should.be.aboveOrEqual(1); + + for (let i in results) { + results[i].date.should.equal(1491718730000.0); + } + }); + + + it('should filter entries by ISO8601 date with timezone', async () => { + let res = await self.instance.get(`${self.url}?date$eq=2017-04-09T12:18:50%2B06:00`, self.jwt.read) + .expect(200); + + res.body.status.should.equal(200); + const results = res.body.result; + const length = results.length; + length.should.be.aboveOrEqual(1); + + for (let i in results) { + results[i].date.should.equal(1491718730000.0); + } + }); + + + it('should filter entries by date range', async () => { + let res = await self.instance.get(`${self.url}?date$gt=1491719030000&date$lt=1491719930000`, self.jwt.read) + .expect(200); + + res.body.status.should.equal(200); + const results = res.body.result; + const length = results.length; + length.should.be.aboveOrEqual(2); + + for (let i in results) { + results[i].date.should.be.above(1491719030000.0); + results[i].date.should.be.below(1491719930000.0); + } + }); + + + it('should accept filter parameters listed in filter_parameters query argument', async () => { + let res = await self.instance.get(`${self.url}?filter_parameters=sgv$eq%3D${testConst.SAMPLE_ENTRIES[4].sgv}`, self.jwt.read) + .expect(200); + + res.body.status.should.equal(200); + const results = res.body.result; + const length = results.length; + length.should.be.aboveOrEqual(1); + + for (let i in results) { + results[i].sgv.should.equal(testConst.SAMPLE_ENTRIES[4].sgv); + } + }); + + + it('should accept multiple filter parameters listed in filter_parameters query argument', async () => { + let res = await self.instance.get(`${self.url}?filter_parameters=date$gt%3D1491719030000%20date$lt%3D1491719930000`, self.jwt.read) + .expect(200); + + res.body.status.should.equal(200); + const results = res.body.result; + const length = results.length; + length.should.be.aboveOrEqual(2); + + for (let i in results) { + results[i].date.should.be.above(1491719030000.0); + results[i].date.should.be.below(1491719930000.0); + } + }); + + it('should skip documents', async () => { let res = await self.instance.get(`${self.url}?sort=date&limit=8`, self.jwt.read) .expect(200);