Simple AWS abstraction library for Node.
Provides a flexible and testable abstraction layer for core AWS application services such as DynamoDB, SNS and SQS so that your code doesn't end up as tightly coupled to the platform. Helps immensely with testability and other concerns related to maintaining a so-called hexagonal architecture. http://alistair.cockburn.us/Hexagonal+architecture
Perfect for Serverless architecture style. Learn more at http://leanpub.com/serverless
npm install saws
Initialize with the AWS
sdk instance.
var AWS = require('aws-sdk');
var Saws = require('saws').Saws;
var saws = new Saws(AWS);
or slightly shorter as:
var AWS = require('aws-sdk');
var saws = new require('saws').Saws(AWS);
The AWS SDK for Node.js doesn't select the region by default. You can choose a region using AWS.config.update()
AWS.config.update({region:'us-east-1'});
Set a value for the stage variable to indicate which environment you're running in. This is useful in conjunction with frameworks such as http://serverless.com
// defaults to 'development'
saws.stage = process.env.SERVERLESS_STAGE;
Now just instantiate saws for tables, topics and queues as needed in your code. Enjoy the simple interface.
Define table params as per Dynamo's createTable
specification. link
var STRIPE_CUSTOMERS_PARAMS = {
TableName: "StripeCustomers",
KeySchema: [
{AttributeName: 'IdentityId', KeyType: 'HASH'},
],
AttributeDefinitions: [
{AttributeName: 'IdentityId', AttributeType: 'S'}
],
ProvisionedThroughput: { ReadCapacityUnits: 2, WriteCapacityUnits: 1 }
};
Then instantiate a saws.Table
object using the params. Note that stage name is appended to the name of the table created.
var customers = new saws.Table(STRIPE_CUSTOMERS_PARAMS);
Delete a record from the table instance.
// You can simply specify the key and value:
customers.delete({
"IdentityId": "id0000001"
}, function(err, data) {
...
});
// Or to use the extended parameters supported by DynamoDB.DocumentClient.delete, specify all params;
customers.delete({
"Key": {
"IdentityId": "id0000001"
},
"ReturnValues": "ALL_OLD"
}, function(err, data) {
...
});
The delete
operation accepts the same paremeters as DynamoDB.DocuemntClient.delete
.
Use the table instance to save records.
customers.save({
"IdentityId": "id0000001",
"StripeCustomerId": "cus_00000001"
}, function(err, data) {
...
});
The save
operation is asynchronous. It takes an object and a callback to be invoked when the operation completes. The object parameter must contain top-level key(s) matching your KeySchema
or the operation will fail. The object parameter may have nested object structures and they will be saved properly similar to the way that MongoDB and other document databases work.
Note: As with all Saws, creation of the underlying resource is automatic. In this case, when saving a record, if the DynamoDB table does not already exist, Saws will create it and wait for it to be available before proceeding with the operation.
Use the table instance to retrieve records.
customers.lookup({"IdentityId": "id0000001"}, function(err, data) {
console.log(data) // => { "IdentityId": "id0000001", "StripeCustomerId": "cus_00000001" },
});
The lookup
operation is asynchronous. It takes a key parameter and a callback to be invoked when the operation completes. The params
object must contain top-level key(s) matching your KeySchema
or the operation will fail.
A thin wrapper around DynamoDB.DocuemntClient.scan
, accepting the same parameters.
The TableName
should not be passed.
Returns one or more items and item attributes by accessing every item in a table or a secondary index.
customers.scan({"Verified": false}, function(err, data) {
console.log(data) // => [{ "IdentityId": "id0000001", "Verified": false}, { "IdentityId": "id0000004", "Verified": false}]
});
Start by instantiating a topic object.
var topic = new saws.Topic("NewOrders");
Creating a Topic
will automatically create an SNS Topic on AWS if it does not already exist. The value of saws.stage
is appended to the topic name.
Send a message using publish
. First argument is the payload, second is a callback to be invoked when publishing is done.
topic.publish("a new order has arrived", function(err, data) { ... });
The callback is invoked when a response from the service is returned. The context of the callback (this
) is set to the response object containing error, data properties, and the original request object.
data
is an object with the de-serialized data returned from the request with a MessageId
property corresponding to the unique identifier string identifier assigned by SNS to the published message.
Payload is automatically run through JSON.stringify()
.
var topic = new saws.Topic("NewOrders");
topic.publish({
NewOrder: {
userId: user.userId,
deliveryAddress: user.deliveryAddress,
stripeSource: user.stripeSource,
preferences: user.preferences
}
}, done);
Convenience object for easily processing SNS events in Lambda functions.
Wrap the event
provided to your Lambda's handler function in a new SNSEvent
object for convenient handling. The SNSEvent instance provides an eachMessage
iterator with a callback that is invoked for each SNS Record
contained in the event. The callback gets two parameters, the whole message object itself and JSON.parse
'd payload.
var chck = require('chck');
// a Lambda function handling an SNS event
exports.handler = function(event, context) {
var e = new saws.SNSEvent(event);
e.eachMessage(function(message, order) {
if(chck(order, {
NewOrder: {
userId: {$present: true}
PaymentReceipt: {$present: true}
FeedbackHistory: {$present: false}
}
})) {
// handle the order...
}
else {
context.success('failed chck guard');
}
});
coming soon
Set SAWS_DEBUG
to true in your environment to enable debug output to the console.
To test your code which uses Saws, you can pass it a stubbed AWS during initialization to ensure no callouts are actually made. For your convenience, one that stubs all services that Saws supports is available as AWSStub
:
var mockSaws = new require('saws').Saws(require('saws').AWSStub);
Now you're able to stub only the Saws methods you need to and pass this as a dependency without worrying about any accidental callouts.