Skip to content

Commit cf16295

Browse files
bflorianerodewald
authored andcommitted
feat: V2.0.0, refactored to add config options and table creation (#3)
* V2.0.0, Refactored to add config options and better support single table apps * Fixes from review comments
1 parent 1b742f6 commit cf16295

File tree

5 files changed

+360
-119
lines changed

5 files changed

+360
-119
lines changed

README.md

Lines changed: 98 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Javascript DynamoDB Context Store
1+
# Javascript DynamoDB Context Store
22

33
Used by the [SmartApp SDK](https://github.com/SmartThingsCommunity/smartapp-sdk-nodejs) to store IDs and access tokens for an installed instance of a SmartApp
44
and retrieves that information for use in asynchronous API calls. The use of a context store
@@ -12,33 +12,114 @@ The context stored by this module consists of the following data elements:
1212
* **locationId**: the UUID of the location in which the app is installed
1313
* **authToken**: the access token used in calling the API
1414
* **refreshToken**: the refresh token used in generating a new access token when one expires
15-
* **clientId**: the SmartApp's client ID, used in generating a new access token
16-
* **clientSecret**: the SmartApp's client secret, used in generating a new access token
17-
* **config**: the current installed app instance configuration, i.e. selected devices, options, etc.v
15+
* **config**: the current installed app instance configuration, i.e. selected devices, options, etc.
16+
17+
_Note: Version 2.X.X is a breaking change to version 1.X.X as far as configuring the context store is
18+
concerned, but either one can be used with any version of the SmartThings SDK._
1819

1920
## Installation:
2021
```
21-
npm install @smartthings/dynamodb-context-store --save
22+
npm install @smartthings/dynamodb-context-store
2223
```
2324

2425
## Usage
2526

26-
To use this module to add DynamoDB context storage to your SmartApp you should:
27-
1. Create a DynamoDB table with `installedAppId` as its primary key
27+
Create a `DynamoDBContextStore` object and pass it to the SmartApp connector to store the context in a table
28+
named `"smartapp"` in the `us-east-1` AWS region. If the table does not exist it will be created.
29+
```javascript
30+
smartapp.contextStore(new DynamoDBContextStore())
31+
```
32+
33+
The more extensive set of options are shown in this example:
34+
```javascript
35+
smartapp.contextStore(new DynamoDBContextStore(
36+
{
37+
table: {
38+
name: 'custom-table', // defaults to 'smartapp'
39+
hashKey: 'key1', // defaults to 'id'
40+
prefix: 'context', // defaults to 'ctx'
41+
readCapacityUnits: 10, // defaults to 5, applies to automatic creation only
42+
writeCapacityUnits: 10 // defaults to 5, applies to automatic creation only
43+
},
44+
AWSRegion: 'us-east-2', // defaults to 'us-east-1'
45+
autoCreate: true // defaults to true
46+
}
47+
))
48+
```
49+
50+
The **table** configuration options are:
51+
* **name** -- The name of the DynamoDB table storing the context
52+
* **hashKey** -- The name of the partition key of the table
53+
* **prefix** -- A string pre-pended to the installed app ID and used as the partition key for the entry
54+
* **readCapacityUnits** -- Number of consistent reads per second. Used only when table is created
55+
* **writeCapacityUnits** -- Number of writes per second. Used only when table is created
56+
* **sortKey** -- Optional sort key definition (see below for more details)
2857

29-
1. Give your Lambda permission to access that table
58+
Other configuration options are:
59+
* **AWSRegion** -- The AWS region containing the table
60+
* **AWSConfigPath** -- The location of the AWS configuration JSON file
61+
* **AWSConfigJSON** -- The AWS credentials and region
62+
* **autoCreate** -- Controls whether table is created if it doesn't already exist
3063

31-
1. Create a context store instance with the table name and AWS region and pass it to the
32-
smartapp SDK object. For example, the following code:
64+
Note that only one of the AWS options should be specified or behavior will be inconsistent
3365

66+
### AWS Configuration Options
67+
68+
By default, the AWS credentials are picked up from the environment. If you prefer you can read the credentials
69+
from a file with this configuration:
70+
```javascript
71+
smartapp.contextStore(new DynamoDBContextStore(
72+
{
73+
AWSConfigPath: './path/to/file.json'
74+
}
75+
))
3476
```
35-
const smartapp = require('@smartthings/dynamodb-context-store');
36-
const DynamoDBContextStore = require('@smartthings/dynamodb-context-store');
3777

38-
smartapp.contextStore(new DynamoDBContextStore('us-east-2', 'app-table-name'))
39-
.configureI18n()
40-
.page('mainPage', (page) => {
41-
...
78+
79+
You can also explicitly set the credentials in this way:
80+
```javascript
81+
smartapp.contextStore(new DynamoDBContextStore(
82+
{
83+
AWSConfigJSON: {
84+
accessKeyId: '<YOUR_ACCESS_KEY_ID>',
85+
secretAccessKey: '<YOUR_SECRET_ACCESS_KEY>',
86+
region: 'us-east-2'
87+
}
88+
}
89+
))
90+
````
91+
92+
### Sort Key Configuration
93+
In order to support single table schemas, the context store can be configured to use a table with a sort key.
94+
The simplest way to do that is by specifying the sort key name:
95+
```javascript
96+
smartapp.contextStore(new DynamoDBContextStore(
97+
{
98+
table: {
99+
name: 'my-application',
100+
hashKey: 'pk',
101+
sortKey: 'sk'
102+
}
103+
}
104+
))
105+
42106
```
107+
More control over the sort key can be exercised using this form, which is configured with the default values
108+
used when just the sort key name is specified:
109+
```javascript
110+
smartapp.contextStore(new DynamoDBContextStore(
111+
{
112+
table: {
113+
name: 'my-application',
114+
hashKey: 'pk',
115+
sortKey: {
116+
AttributeName: 'sk',
117+
AttributeType: 'S',
118+
AttributeValue: 'context',
119+
KeyType: 'RANGE'
120+
}
121+
}
122+
}
123+
))
43124
44-
will use a table named `app-table-name` in the `us-east-2` region.
125+
```

index.js

Lines changed: 1 addition & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,3 @@
11
'use strict';
2-
const AWS = require('aws-sdk');
32

4-
module.exports = class DynamoDBContextStore {
5-
constructor(region, tableName) {
6-
this.region = region;
7-
this.tableName = tableName;
8-
AWS.config.update({region: region});
9-
this.docClient = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
10-
}
11-
12-
get(installedAppId) {
13-
let params = {
14-
TableName: this.tableName,
15-
Key: {
16-
installedAppId: installedAppId
17-
},
18-
ConsistentRead: true
19-
};
20-
return new Promise((resolve, reject) => {
21-
this.docClient.get(params, function(err, data) {
22-
if (err) {
23-
reject(err);
24-
} else {
25-
if (data.Item) {
26-
let result = data.Item;
27-
28-
// For backward compatibility with version 1.0.1
29-
if (typeof result.config === 'string') {
30-
result.config = JSON.parse(result.config);
31-
}
32-
resolve(result);
33-
}
34-
else {
35-
resolve({});
36-
}
37-
}
38-
});
39-
});
40-
}
41-
42-
put(params) {
43-
const data = {
44-
TableName: this.tableName,
45-
Item: {
46-
installedAppId: params.installedAppId,
47-
locationId: params.locationId,
48-
authToken: params.authToken,
49-
refreshToken: params.refreshToken,
50-
config: params.config
51-
}
52-
};
53-
return new Promise((resolve, reject) => {
54-
this.docClient.put(data, function(err, data) {
55-
if (err) {
56-
reject(err);
57-
} else {
58-
resolve(data);
59-
}
60-
});
61-
});
62-
}
63-
64-
update(installedAppId, params) {
65-
const data = {
66-
TableName: this.tableName,
67-
Key: {'installedAppId': installedAppId},
68-
UpdateExpression: 'SET authToken = :x, refreshToken = :y',
69-
ExpressionAttributeValues: {
70-
':x': params.authToken,
71-
':y': params.refreshToken
72-
}
73-
};
74-
return new Promise((resolve, reject) => {
75-
this.docClient.update(data, function(err, data) {
76-
if (err) {
77-
reject(err);
78-
} else {
79-
resolve(data);
80-
}
81-
});
82-
});
83-
}
84-
85-
delete(installedAppId) {
86-
let params = {
87-
TableName: this.tableName,
88-
Key: {
89-
installedAppId: installedAppId
90-
}
91-
};
92-
return new Promise((resolve, reject) => {
93-
this.docClient.delete(params, function(err, data) {
94-
if (err) {
95-
reject(err);
96-
} else {
97-
resolve(data);
98-
}
99-
});
100-
});
101-
}
102-
};
3+
module.exports = require('./lib/DynamoDBContextStore')

0 commit comments

Comments
 (0)