Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API V3 #4250

Merged
merged 151 commits into from
Oct 9, 2019
Merged

API V3 #4250

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
151 commits
Select commit Hold shift + click to select a range
589f61d
extended .gitignore for Visual Studio 2017
PetrOndrusek Feb 1, 2019
c0b265b
creating a lib for api3 and exposing it's swagger file
PetrOndrusek Feb 1, 2019
9e7b0de
adding pilot test (for /swagger.yaml)
PetrOndrusek Feb 1, 2019
403bce4
implementing public GET /version
PetrOndrusek Feb 1, 2019
bdb880d
setting api version to 3.0.0-alpha
PetrOndrusek Feb 2, 2019
48c3fa5
creating authorization skeleton + fetching some API env variables
PetrOndrusek Feb 2, 2019
cc4fb5b
reusing authorization library
PetrOndrusek Feb 3, 2019
3d382d0
implementing security
PetrOndrusek Feb 3, 2019
12d9315
forcing HTTPS and removing x-powered-by from response
PetrOndrusek Feb 4, 2019
e109d03
moving messages to constants, creating https instance fixture
PetrOndrusek Feb 4, 2019
f3580e2
testing HTTPS requiring
PetrOndrusek Feb 4, 2019
5cd47d6
testing Date header
PetrOndrusek Feb 5, 2019
4d68645
testing permission check
PetrOndrusek Feb 5, 2019
4e2153a
testing allowed operation
PetrOndrusek Feb 6, 2019
d077e7c
refactoring + storage stub
PetrOndrusek Feb 7, 2019
22faa60
create architecture for generic operations
PetrOndrusek Feb 7, 2019
bd89bfb
beginning of READ operation
PetrOndrusek Feb 12, 2019
71db189
tidying the code up
PetrOndrusek Feb 13, 2019
b9d0920
basic READ part
PetrOndrusek Feb 13, 2019
30870b6
going further with READ operation
PetrOndrusek Feb 13, 2019
7bff23a
DELETE operation
PetrOndrusek Feb 19, 2019
5ee6b1f
handling fields parameter
PetrOndrusek Feb 21, 2019
c1b7b03
refactoring to classes
PetrOndrusek Feb 22, 2019
91096c3
Merge remote-tracking branch 'base/dev' into wip/api3
PetrOndrusek Mar 3, 2019
cbc7f1d
going further with SEARCH operation
PetrOndrusek Mar 4, 2019
2477690
refactoring file structure
PetrOndrusek Mar 5, 2019
83a6747
filtering for SEARCH operation
PetrOndrusek Mar 13, 2019
632b544
preparations for fallback deduplication
PetrOndrusek Mar 13, 2019
c2e58cf
CREATE operation
PetrOndrusek Mar 19, 2019
b95cea0
UPDATE operation
PetrOndrusek Mar 20, 2019
c0a0e19
PATCH operation
PetrOndrusek Mar 21, 2019
ac53109
HISTORY operation
PetrOndrusek Mar 21, 2019
5901686
creating more precise variant of HISTORY operation
PetrOndrusek Mar 21, 2019
8fc76a4
autopruning
PetrOndrusek Mar 23, 2019
81291dc
long for timestamps in swagger
PetrOndrusek Mar 27, 2019
d4ecca9
bug fix (when search fields=srvCreated)
PetrOndrusek Apr 1, 2019
9a404b5
creating skeleton for generic collection API test
PetrOndrusek Apr 11, 2019
1e5b3e0
specific HISTORY skeleton
PetrOndrusek Apr 16, 2019
515076b
distinguish between collection logical and storage name
PetrOndrusek Apr 16, 2019
d566b37
renaming operation to LAST MODIFIED and getting it to work
PetrOndrusek Apr 17, 2019
f2e445c
fallback for LAST MODIFIED operation
PetrOndrusek Apr 23, 2019
94bfcdb
tidying a bit
PetrOndrusek Apr 24, 2019
8203760
LAST MODIFIED documentation
PetrOndrusek Apr 26, 2019
9b447b7
bugfix + emitting data-received
PetrOndrusek Apr 26, 2019
069fa4f
merge dev
PetrOndrusek Apr 26, 2019
bf49c82
adding some validations
PetrOndrusek Apr 26, 2019
194cfd9
bugfix - remove 'token' parameter from filtering
PetrOndrusek Apr 30, 2019
be2c35a
testing and debugging generic workflow
PetrOndrusek May 8, 2019
4dec6e9
test fix for empty db
PetrOndrusek May 8, 2019
6254c06
fixing security test fixture
PetrOndrusek May 9, 2019
b7b878c
trying to fix Travis CI testing DB problem
PetrOndrusek May 9, 2019
d409902
merge dev
PetrOndrusek May 10, 2019
741000b
multiple auth callback bugfix + adding user field on authed create/up…
PetrOndrusek May 12, 2019
bcd2563
messages for Travis CI debugging
PetrOndrusek May 12, 2019
8ed90b7
messages for Travis CI debugging
PetrOndrusek May 12, 2019
1d34d6d
messages for Travis CI debugging
PetrOndrusek May 12, 2019
7480956
test fix (to be prepared for future dates in db)
PetrOndrusek May 12, 2019
b63524f
test fix
PetrOndrusek May 12, 2019
ba4c40f
adding fallback created_at filling on each create/update
PetrOndrusek May 12, 2019
c835851
merge dev
PetrOndrusek May 21, 2019
faa571d
STATUS operation with API permissions
PetrOndrusek May 21, 2019
7fc66c9
querying srvDate from storage + include storage version info
PetrOndrusek May 21, 2019
ab47c5b
bugfix of missing apiConst require
PetrOndrusek May 21, 2019
a5ed6d7
getting mongo version with read-only user rights
PetrOndrusek May 30, 2019
2454b38
getting mongo current date with read-only user rights
PetrOndrusek May 30, 2019
90c19ca
trying to diagnose travis CI timeout
PetrOndrusek May 30, 2019
bcbbefd
refactoring storage version caching (due to some environments problems)
PetrOndrusek May 30, 2019
48d53bf
making VERSION work on empty database
PetrOndrusek May 30, 2019
55b01b8
more fixes
PetrOndrusek May 30, 2019
e689e44
skipping API HTTPS test for node 8
PetrOndrusek May 31, 2019
589e032
making code more readable using ES6 (Promises, async + await)
PetrOndrusek Jun 4, 2019
23f7c0a
extending treatments collection docs by inspecting the careportal code
PetrOndrusek Jun 4, 2019
5b57b8b
tidying existing API3 tests up to allow further grow
PetrOndrusek Jun 5, 2019
a637a01
tidying the authorization code up to increase readability and perform…
PetrOndrusek Jun 6, 2019
5b1e76a
more refactoring to ES6 and making APIv3 files structure more extendable
PetrOndrusek Jun 6, 2019
6776123
normalizing incoming dates to UTC and storing utcOffset
PetrOndrusek Jun 6, 2019
4839cc7
fixing srvDate to be of node.js server, not the mongo DB
PetrOndrusek Jun 6, 2019
915ae27
preparing test fixtures for permissions testing + skeleton for CREATE…
PetrOndrusek Jun 8, 2019
ce7cb83
intensive CREATE operation testing + minor bug fixes
PetrOndrusek Jun 10, 2019
25b1581
correcting the deduplication test
PetrOndrusek Jun 10, 2019
c6a9fc8
more deduplication testing of CREATE operation
PetrOndrusek Jun 11, 2019
ba22273
adding test skeletons for other generic operations
PetrOndrusek Jun 12, 2019
543251c
added variability in filtering by date, created_at, srvModified, srvC…
PetrOndrusek Jun 12, 2019
92f8bc0
fixing test accordingly to previous commit
PetrOndrusek Jun 12, 2019
757f57e
adding new collection settings for centralized apps' settings storage
PetrOndrusek Jun 12, 2019
15f617e
trying to solve travis CI testing problem - adding default collection…
PetrOndrusek Jun 12, 2019
d5d8e88
another attempt to travis CI test fix
PetrOndrusek Jun 12, 2019
f27faf5
adding some tests for READ operation
PetrOndrusek Jun 13, 2019
6ce6c2e
adding custom error handler (overriding bodyparser's errors)
PetrOndrusek Jun 13, 2019
a20ce3a
securing settings collection more and updating swagger accordingly
PetrOndrusek Jun 13, 2019
c951ea8
making HISTORY timestamp parameter more flexible + updating swagger d…
PetrOndrusek Jun 14, 2019
e203d1a
more testing and bug fixing
PetrOndrusek Jun 14, 2019
43af4c0
sending only HTTP status with empty body, when there is no message + …
PetrOndrusek Jun 14, 2019
1b307b0
more refactoring and testing (especially of UPDATE operation)
PetrOndrusek Jun 16, 2019
a858c3d
PATCH testing + adding userModified field for troubleshooting purposes
PetrOndrusek Jun 16, 2019
ba5248f
basic SEARCH operation testing
PetrOndrusek Jun 17, 2019
6c6e4c3
more SEARCH operation testing
PetrOndrusek Jun 18, 2019
9b7dd8f
adding alternative 'now' query parameter to 'Date' header to make GET…
PetrOndrusek Jun 19, 2019
c98764e
adding 'now' to reserved query parameters for SEARCH operation
PetrOndrusek Jun 19, 2019
07472d1
more testing
PetrOndrusek Jul 6, 2019
832f9b0
renaming field user to subject (and modifiedBy)
PetrOndrusek Jul 8, 2019
6a15763
Merge remote-tracking branch 'nsteam/dev' into wip/api3
PetrOndrusek Jul 8, 2019
3b1d594
bugfix - fixing RFC 2822 constant for moment parsing
PetrOndrusek Jul 9, 2019
2351125
storageSocket: creating skeleton for new Socket.IO namespace
PetrOndrusek Jul 12, 2019
8882d3a
storageSocket: authentication by accessToken
PetrOndrusek Jul 13, 2019
4075881
storageSocket: authorizing to subscribe rooms
PetrOndrusek Jul 20, 2019
7b7d5cf
storageSocket: emitting create, update and delete events
PetrOndrusek Jul 20, 2019
b22ce89
Merge remote-tracking branch 'nsteam/dev' into wip/api3-socket
PetrOndrusek Jul 20, 2019
02fa57a
APIv3: adding support for swagger UI at /api/v3/swagger-ui-dist
PetrOndrusek Jul 21, 2019
5781f83
solving some problems detected by eslint
PetrOndrusek Jul 22, 2019
58daac4
solving some problems detected by eslint
PetrOndrusek Jul 22, 2019
6ab8efd
APIv3: testing and debugging Socket.IO
PetrOndrusek Jul 25, 2019
30dd3e0
APIv3: testing and debugging Socket.IO
PetrOndrusek Jul 25, 2019
dbe59ff
APIv3: Socket.IO documentation
PetrOndrusek Jul 26, 2019
47514f2
APIv3: making the sample real
PetrOndrusek Jul 27, 2019
b894583
APIv3: starting to create a simple tutorial MD file
PetrOndrusek Jul 29, 2019
c335596
APIv3: small corrections
PetrOndrusek Jul 29, 2019
daa727d
Merge remote-tracking branch 'nsteam/dev' into wip/api3
PetrOndrusek Jul 29, 2019
cd16825
APIv3: minor corrections after dev merge
PetrOndrusek Jul 30, 2019
bbbd90f
APIv3: adding CREATE and READ operations to the tutorial.md
PetrOndrusek Jul 30, 2019
fff6cec
APIv3: adding SEARCH, LAST MODIFIED, UPDATE operations to the tutoria…
PetrOndrusek Jul 30, 2019
f4e1cbd
APIv3: finishing the tutorial.md
PetrOndrusek Jul 31, 2019
e5c7902
APIv3: minor bugfix (bad location after upsert)
PetrOndrusek Aug 1, 2019
a0b24aa
APIv3: refactoring SEARCH complexity
PetrOndrusek Aug 2, 2019
d56fb62
APIv3: refactoring mongoCollection complexity
PetrOndrusek Aug 2, 2019
0e1fb22
APIv3: refactoring complexity
PetrOndrusek Aug 2, 2019
55acb66
APIv3: tidying up a bit
PetrOndrusek Aug 3, 2019
04db4ef
APIv3: refactoring security (start)
PetrOndrusek Aug 3, 2019
a55aa15
APIv3: refactoring lastModified
PetrOndrusek Aug 3, 2019
e796d17
APIv3: refactoring create (start)
PetrOndrusek Aug 3, 2019
fb940aa
APIv3: refactoring create (finish)
PetrOndrusek Aug 3, 2019
6c3ca87
APIv3: refactoring delete
PetrOndrusek Aug 4, 2019
a6960f3
APIv3: refactoring history
PetrOndrusek Aug 4, 2019
30d58e9
APIv3: refactoring update
PetrOndrusek Aug 4, 2019
9e5893b
APIv3: refactoring patch
PetrOndrusek Aug 4, 2019
810030b
APIv3: refactoring read
PetrOndrusek Aug 4, 2019
6152e99
APIv3: refactoring search + removing deprecated authorizationBuilder
PetrOndrusek Aug 4, 2019
c51028b
APIv3: adding best practise for identifier constructing
PetrOndrusek Aug 5, 2019
fbeb792
APIv3: refactoring and enhancing the validation (immutable fields)
PetrOndrusek Aug 5, 2019
e24d40d
Merge remote-tracking branch 'nsteam/dev' into wip/api3
PetrOndrusek Aug 5, 2019
881e673
APIv3: adding security.md documentation file
PetrOndrusek Aug 5, 2019
a2f093e
APIv3: refactoring - splitting index.js into multiple files
PetrOndrusek Aug 14, 2019
e3eb5be
APIv3: calculating identifier on server side + deduplicating
PetrOndrusek Aug 14, 2019
6183f49
APIv3: refactoring cosmetics
PetrOndrusek Aug 15, 2019
89dc589
Merge remote-tracking branch 'nsteam/dev' into wip/api3
PetrOndrusek Aug 15, 2019
df1198a
APIv3: updating the documentation
PetrOndrusek Aug 15, 2019
5695ab4
APIv3: making basic and security tests more readable using async/await
PetrOndrusek Aug 26, 2019
437a842
Merge remote-tracking branch 'nsteam/dev' into wip/api3
PetrOndrusek Aug 26, 2019
b1a98ad
APIv3: making the rest of tests more readable using async/await
PetrOndrusek Aug 26, 2019
fb80d75
APIv3: adapting test of previous API
PetrOndrusek Aug 27, 2019
830efed
APIv3: adapting test of previous API
PetrOndrusek Aug 27, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ module.exports = {
"commonjs": true,
"es6": true,
"node": true,
"mocha": true,
"jquery": true
},
"rules": {
"no-unused-vars": [
"error",
{
"varsIgnorePattern": "should|expect"
}
]
}
};
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ npm-debug.log
*.heapsnapshot

/tmp
/.vs
/cgm-remote-monitor.njsproj
/cgm-remote-monitor.sln
/obj/Debug
/bin
/*.bat
13 changes: 8 additions & 5 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,12 @@ function create (env, ctx) {
});
}

///////////////////////////////////////////////////
// api and json object variables
///////////////////////////////////////////////////
var api = require('./lib/api/')(env, ctx);
var ddata = require('./lib/data/endpoints')(env, ctx);
///////////////////////////////////////////////////
// api and json object variables
///////////////////////////////////////////////////
var api = require('./lib/api/')(env, ctx);
var api3 = require('./lib/api3/')(env, ctx);
var ddata = require('./lib/data/endpoints')(env, ctx);

app.use(compression({
filter: function shouldCompress (req, res) {
Expand Down Expand Up @@ -172,6 +173,8 @@ function create (env, ctx) {
app.use('/api/v2/authorization', ctx.authorization.endpoints);
app.use('/api/v2/ddata', ddata);

app.use('/api/v3', api3);

// pebble data
app.get('/pebble', ctx.pebble);

Expand Down
1 change: 1 addition & 0 deletions env.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ function setStorage() {
env.authentication_collections_prefix = readENV('MONGO_AUTHENTICATION_COLLECTIONS_PREFIX', 'auth_');
env.treatments_collection = readENV('MONGO_TREATMENTS_COLLECTION', 'treatments');
env.profile_collection = readENV('MONGO_PROFILE_COLLECTION', 'profile');
env.settings_collection = readENV('MONGO_SETTINGS_COLLECTION', 'settings');
env.devicestatus_collection = readENV('MONGO_DEVICESTATUS_COLLECTION', 'devicestatus');
env.food_collection = readENV('MONGO_FOOD_COLLECTION', 'food');
env.activity_collection = readENV('MONGO_ACTIVITY_COLLECTION', 'activity');
Expand Down
51 changes: 51 additions & 0 deletions lib/api3/const.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"API3_VERSION": "3.0.0-alpha",
"API3_SECURITY_ENABLE": true,
"API3_TIME_SKEW_TOLERANCE": 5,
"API3_DEDUP_FALLBACK_ENABLED": true,
"API3_CREATED_AT_FALLBACK_ENABLED": true,
"API3_MAX_LIMIT": 1000,

"HTTP": {
"OK": 200,
"CREATED": 201,
"NO_CONTENT": 204,
"NOT_MODIFIED": 304,
"BAD_REQUEST": 400,
"UNAUTHORIZED": 401,
"FORBIDDEN": 403,
"NOT_FOUND": 404,
"GONE": 410,
"PRECONDITION_FAILED": 412,
"INTERNAL_ERROR": 500
},

"MSG": {
"HTTP_400_BAD_LAST_MODIFIED": "Bad or missing Last-Modified header/parameter",
"HTTP_400_BAD_LIMIT": "Parameter limit out of tolerance",
"HTTP_400_BAD_REQUEST_BODY": "Bad or missing request body",
"HTTP_400_BAD_FIELD_IDENTIFIER": "Bad or missing identifier field",
"HTTP_400_BAD_FIELD_DATE": "Bad or missing date field",
"HTTP_400_BAD_FIELD_UTC": "Bad or missing utcOffset field",
"HTTP_400_BAD_FIELD_APP": "Bad or missing app field",
"HTTP_400_BAD_SKIP": "Parameter skip out of tolerance",
"HTTP_400_SORT_SORT_DESC": "Parameters sort and sort_desc cannot be combined",
"HTTP_400_UNSUPPORTED_FILTER_OPERATOR": "Unsupported filter operator {0}",
"HTTP_400_IMMUTABLE_FIELD": "Field {0} cannot be modified by the client",
"HTTP_401_BAD_DATE": "Bad Date header",
"HTTP_401_BAD_TOKEN": "Bad access token or JWT",
"HTTP_401_DATE_OUT_OF_TOLERANCE": "Date header out of tolerance",
"HTTP_401_MISSING_DATE": "Missing Date header",
"HTTP_401_MISSING_OR_BAD_TOKEN": "Missing or bad access token or JWT",
"HTTP_403_MISSING_PERMISSION": "Missing permission {0}",
"HTTP_403_NOT_USING_HTTPS": "Not using SSL/TLS",
"HTTP_500_INTERNAL_ERROR": "Internal Server Error",
"STORAGE_ERROR": "Database error",
"SOCKET_MISSING_OR_BAD_ACCESS_TOKEN": "Missing or bad accessToken",
"SOCKET_UNAUTHORIZED_TO_ANY": "Unauthorized to receive any collection"
},

"MIN_TIMESTAMP": 946684800000,
"MIN_UTC_OFFSET": -1440,
"MAX_UTC_OFFSET": 1440
}
48 changes: 48 additions & 0 deletions lib/api3/doc/security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# APIv3: Security

### Enforcing HTTPS
APIv3 is ment to run only under SSL version of HTTP protocol, which provides:
- **message secrecy** - once the secure channel between client and server is closed the communication cannot be eavesdropped by any third party
- **message consistency** - each request/response is protected against modification by any third party (any forgery would be detected)
- **authenticity of identities** - once the client and server establish the secured channel, it is guaranteed that the identity of the client or server does not change during the whole session

HTTPS (in use with APIv3) does not address the true identity of the client, but ensures the correct identity of the server. Furthermore, HTTPS does not prevent the resending of previously intercepted encrypted messages by an attacker.


---
### Authentication and authorization
In APIv3, *API_SECRET* can no longer be used for authentication or authorization. Instead, a roles/permissions security model is used, which is managed in the *Admin tools* section of the web application.


The identity of the client is represented by the *subject* to whom the access level is set by assigning security *roles*. One or more *permissions* can be assigned to each role. Permissions are used in an [Apache Shiro-like style](http://shiro.apache.org/permissions.html "Apache Shiro-like style").


For each security *subject*, the system automatically generates an *access token* that is difficult to guess since it is derived from the secret *API_SECRET*. The *access token* must be included in every secured API operation to decode the client's identity and determine its authorization level. In this way, it is then possible to resolve whether the client has the permission required by a particular API operation.


There are two ways to authorize API calls:
- use `token` query parameter to pass the *access token*, eg. `token=testreadab-76eaff2418bfb7e0`
- use so-called [JSON Web Tokens](https://jwt.io "JSON Web Tokens")
- at first let the `/api/v2/authorization/request` generates you a particular JWT, eg. `GET https://nsapiv3.herokuapp.com/api/v2/authorization/request/testreadab-76eaff2418bfb7e0`
- then, to each secure API operation attach a JWT token in the HTTP header, eg. `Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NUb2tlbiI6InRlc3RyZWFkYWItNzZlYWZmMjQxOGJmYjdlMCIsImlhdCI6MTU2NTAzOTczMSwiZXhwIjoxNTY1MDQzMzMxfQ.Y-OFtFJ-gZNJcnZfm9r4S7085Z7YKVPiaQxuMMnraVk` (until the JWT expires)



---
### Client timestamps
As previously mentioned, a potential attacker cannot decrypt the captured messages, but he can send them back to the client/server at any later time. APIv3 is partially preventing this by the temporal validity of each secured API call.


The client must include his current timestamp to each call so that the server can compare it against its clock. If the timestamp difference is not within the limit, the request is considered invalid. The tolerance limit is set in minutes in the `API3_TIME_SKEW_TOLERANCE` environment variable.

There are two ways to include the client timestamp to the call:
- use `now` query parameter with UNIX epoch millisecond timestamp, eg. `now=1565041446908`
- add HTTP `Date` header to the request, eg. `Date: Sun, 12 May 2019 07:49:58 GMT`


The client can check each server response in the same way, because each response contains a server timestamp in the HTTP *Date* header as well.


---
APIv3 security is enabled by default, but it can be completely disabled for development and debugging purposes by setting the web environment variable `API3_SECURITY_ENABLE=false`.
This setting is hazardous and it is strongly discouraged to be used for production purposes!
142 changes: 142 additions & 0 deletions lib/api3/doc/socket.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# APIv3: Socket.IO storage modifications channel

APIv3 has the ability to broadcast events about all created, edited and deleted documents, using Socket.IO library.

This provides a real-time data exchange experience in combination with API REST operations.

### Complete sample client code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

<title>APIv3 Socket.IO sample</title>

<link rel="icon" href="images/favicon.png" />
</head>

<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>

<script>
const socket = io('https://nsapiv3.herokuapp.com/storage');

socket.on('connect', function () {
socket.emit('subscribe', {
accessToken: 'testadmin-ad3b1f9d7b3f59d5',
collections: [ 'entries', 'treatments' ]
}, function (data) {
if (data.success) {
console.log('subscribed for collections', data.collections);
}
else {
console.error(data.message);
}
});
});

socket.on('create', function (data) {
console.log(`${data.colName}:created document`, data.doc);
});

socket.on('update', function (data) {
console.log(`${data.colName}:updated document`, data.doc);
});

socket.on('delete', function (data) {
console.log(`${data.colName}:deleted document with identifier`, data.identifier);
});
</script>
</body>
</html>
```

**Important notice: Only changes made via APIv3 are being broadcasted. All direct database or APIv1 modifications are not included by this channel.**

### Subscription (authorization)
The client must first subscribe to the channel that is exposed at `storage` namespace, ie the `/storage` subadress of the base Nightscout's web address (without `/api/v3` subaddress).
```javascript
const socket = io('https://nsapiv3.herokuapp.com/storage');
```


Subscription is requested by emitting `subscribe` event to the server, while including document with parameters:
* `accessToken`: required valid accessToken of the security subject, which has been prepared in *Admin Tools* of Nightscout.
* `collections`: optional array of collections which the client wants to subscribe to, by default all collections are requested)

```javascript
socket.on('connect', function () {
socket.emit('subscribe', {
accessToken: 'testadmin-ad3b1f9d7b3f59d5',
collections: [ 'entries', 'treatments' ]
},
```


On the server, the subject is first identified and authenticated (by the accessToken) and then a verification takes place, if the subject has read access to each required collection.

An exception is the `settings` collection for which `api:settings:admin` permission is required, for all other collections `api:<collection>:read` permission is required.


If the authentication was successful and the client has read access to at least one collection, `success` = `true` is set in the response object and the field `collections` contains an array of collections which were actually subscribed (granted).
In other case `success` = `false` is set in the response object and the field `message` contains an error message.

```javascript
function (data) {
if (data.success) {
console.log('subscribed for collections', data.collections);
}
else {
console.error(data.message);
}
});
});
```

### Receiving events
After the successful subscription the client can start listening to `create`, `update` and/or `delete` events of the socket.


##### create
`create` event fires each time a new document is inserted into the storage, regardless of whether it was CREATE or UPDATE operation of APIv3 (both of these operations are upserting/deduplicating, so they are "insert capable"). If the document already existed in the storage, the `update` event would be fired instead.

The received object contains:
* `colName` field with the name of the affected collection
* the inserted document in `doc` field

```javascript
socket.on('create', function (data) {
console.log(`${data.colName}:created document`, data.doc);
});
```


##### update
`update` event fires each time an existing document is modified in the storage, regardless of whether it was CREATE, UPDATE or PATCH operation of APIv3 (all of these operations are "update capable"). If the document did not yet exist in the storage, the `create` event would be fired instead.

The received object contains:
* `colName` field with the name of the affected collection
* the new version of the modified document in `doc` field

```javascript
socket.on('update', function (data) {
console.log(`${data.colName}:updated document`, data.doc);
});
```


##### delete
`delete` event fires each time an existing document is deleted in the storage, regardless of whether it was "soft" (marking as invalid) or permanent deleting.

The received object contains:
* `colName` field with the name of the affected collection
* the identifier of the deleted document in the `identifier` field

```javascript
socket.on('delete', function (data) {
console.log(`${data.colName}:deleted document with identifier`, data.identifier);
});
```
Loading