theta
v0.0.0
Published
[![NPM version][npm-image]][npm-url] [![Build status][travis-image]][travis-url] [![Test coverage][codecov-image]][codecov-url] [![Dependency Status][david-image]][david-url] [![License][license-image]][license-url] [![Downloads][downloads-image]][downloa
Downloads
7
Maintainers
Readme
theta
Slowly modularize your app into AWS Lambda Functions.
Example
In our example, we create a lambda function around bcryptjs. Password hashing is a good use-case for lambda since it's CPU intensive, is a very simple function, and can be easily outsourced to Lambda.
Calling Lambdas
Suppose you have lambda functions bcrypt-compare
and bcrypt-hash
defined in your app:
lambdas/
bcrypt-compare/
index.js
lambda.json
package.json
bcrypt-hash/
index.js
lambda.json
package.json
server/
index.js
From server/index.js
, you can theta/require
any lambda function:
import lambda from 'theta/require'
const bcryptCompare = lambda('bcrypt-compare')
bcryptCompare({
password: 'mypassword',
hash: '$some$bcrypt$hash',
}).then(valid => {
console.log(valid)
})
By default, the local version of the lambda is used. In other words, in development, AWS Lambdas are not actually used. This makes development and testing both simpler and faster.
In production, lambdas are used by default.
You can also enable lambdas using the environment variable THETA_ENABLED=1
.
Creating Lambdas
Each lambda could have its own dependencies via package.json
.
For example, lambdas/bcrypt-compare
might have:
{
"dependencies": {
"bcryptjs": "^2.0.0"
}
}
However, you could also require other modules within your app and not define your explicitly require()
d dependencies in each lambda.
import fn from '../../lib/fn'
export default function (event, context) {
return fn(event).then(val => context.succeed(val), err => context.fail(err))
}
theta
will:
- Automatically transpile the code to node v0.12 code via babel - some configuration may be required.
- Bundle your lambda into a single file (like webpack/browserify, but not).
- Install dependencies in each lambda which may or may not be defined in the local
package.json
by crawling through the dependency tree.
Publishing
Each lambda is published with its package.json
's name and the git repository's git commit as the version.
This means that each commit of your app will have its own set of lambdas.
The publishing logic is as follows:
- Create a temporary directory for each lambda
- Copy over the
package.json
- Compile the lambda's
index.js
file and save it into the temporary directory asindex.js
npm install --save
all the crawled dependencies of the lambda- Package the folder into a zip
- Publish the zip to AWS Lambda with the git commit as the version
Compiling is done with the theta push
command.
Testing
Each lambda should have its own tests.
theta test
will run all of your lambdas' tests locally.
theta
will run the tests using lambdas after publishing.
You could test your app both with and without Lambdas.
One way is to run parallel tests (one test with THETA_ENABLED=1
, one without).
Another is to run separate tests (i.e. Lambda functions only) in parallel to actual tests.
theta push
takes a while to run.
It's intended to be run in your CI, never locally.
Here's what your test script could look like:
# run tests locally without remote lambdas
npm test
# create your lambda functions
./node_modules/theta push
# run the tests again with remote lambdas
THETA_ENABLED=1 npm test
API
theta(1)
theta push
Push all your lambda functions to AWS.
Options:
--test
- run all the tests against the lambda functions as they are published
theta test
Run all your lambda tests locally.
node.js
import lambda from 'theta/require'
Acts kind of like require()
.
See below:
const fn = lambda(name, [options])
Require a lambda function. Depending on the configuration, this could just run the JS locally or it could be running the lambda remotely.
name
- the name of the lambda
The first set of options are the Lambda Invoke options:
InvocationType
LogType
Qualifier
The second set of options are theta
options:
remote
- overridingTHETA_ENABLED
, whether to use a Lambda
fn(event, [context]).then(result => {})
Calls a lambda function.
context
is optional.
The function always returns a Promise
instance,
even if the underlying lambda function is synchronous.
configuration
Environment Variables
theta
environment variables:
THETA_ENABLED <optional>
- whethertheta/require
uses lambdas or not.THETA_PATH <optional>
- the path of thelambdas/
folder defaulting topath.resolve('lambdas')
AWS environment variables (which can just be set in lambdas/config.js
below):
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
AWS_REGION
AWS_LAMBDA_ROLE
lambdas/package.json
lambdas/.babelrc
The babel configuration to be used when bundling your lambda function. If not defined, the following configuration will be used:
{
"presets": [
"stage-0",
"es2015",
]
}
Note that this will overwrite any other .babelrc
.
lambdas/config.js
Configuration for all your lambdas.
lambdas//lambda.json
Optional options for each of your lambdas
Notes
- Slowly split your code into separate files.
This will allow your lambda functions to remain minimal as
theta
will include anyrequire()
d modules in the lambda. For example, refactor to doimport fn from 'lib/fn'
instead ofimport { fn } from 'lib'
- Because modules are packaged together,
certain node features such as
__dirname
and__filename
are not supported. Do not use these when the module will be used in lambda functions. - If a dependency is not explicitly
import
ed down the lambda's dependency tree, you should add it in the lambda'spackage.json
orlambdas/package.json
.