fsp-cli
v6.3.1
Published
Rapidly develop small scale, inexpensive, servless applications by leveraging AWS.
Downloads
16
Readme
This project has been succeeded by the much better project: Infarep. Use Infarep in conjunction with infarep-aws.
fsp (Fast Serverless Prototyping)
A javascript framework to help small businesses rapidly develop inexpensive, serverless applications through AWS.
Features
- Quickly spin up Aurora Serverless DBs, API Gateway Endpoints, S3 Buckets, Lambda Functions, and IAM objects.
- Deploy multiple instances of your application on the same AWS account (for example: dev AND prod environments)
- Deploy or teardown your entire application with a single command.
- Easily invoke one lambda in your application from another lambda in your application.
- Automatically authorize your lambda functions to access the other components in your project.
- Setup third party services during deployment and tear them down during the teardown phase.
User Guide
Filesystem Structure
Every fsp project uses the same basic structure.
mkdir myServerlessPrototype
- Create a directory to store all of your app's files. The name of this directory is also used as the name of your app.
cd myServerlessPrototype
touch glue.js
- This is where you will declare your application's components. For example: Lambda Functions, Aurora Databases, IAM Roles, IAM Policies, Redis Caches, API Gateway Endpoints, etc. We will fill this file out in a later step.
- Declare your cloud environments. Here we are making one for development/testing and another for production. We will fill these files out in a later step.
touch devCloud.js
touch prodCloud.js
Deployment Environments
Cloud Environment Declaration Files (CED Files)
A CED File represents an instance of your application. This is where you declare the AWS account and region you would like to use.
- The name of CED Files must always be in the format
<someName>Cloud.js
. (Ex.prodCloud.js
,devCloud.js
. ) - The file must be placed in the root directory of the application.
- A typical CED File looks like this:
const { SharedIniFileCredentials } = require('aws-sdk'); module.exports = { aws: { region: 'us-east-2', credentials: new SharedIniFileCredentials({ profile: 'work-account' }) }, vpc: { securityGroupIds: ['sg-123'], // Lambda Functions will be placed in these security groups. subnetIds: ['sn-123'] // Lambdas & Databases will be placed in these subnets. } };
- There is no limit to the number of instances an application can have in one region, account, or vpc. Making a new environment is as easy as creating another CED File. You will learn how to deploy to these environments in a later step.
Glue File
Every fsp project has a glue.js
file that declares all the components of the application.
- A glue file must export only one function. You will fill this function with component declarations. Components are things like databases, Lambda Functions, IAM Roles, etc.
module.exports = function() {}
- Every component in an application must have a unique name. The name should be explicitly stated using
this.myName = componentType();
syntax. - There is no limit on the numer of components you can declare. For example: your app could declare 100s of unique S3 buckets.
Component Types
Component Declaration: Database
this.db0 = autoscalingPostgresqlDb({ dbSubnetGroup: this.projectDbSubnetGroup });
Component Declaration: IAM Policy
this.somePolicy = iamPolicy({ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [], "Resource": ["*"] }] }); // Or, if you need to reference a declared component use this structure... this.somePolicy = iamPolicy(function() { return { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [], "Resource": [this.someDeclaredComponent.externalIdentity.arn] }] } }.bind(getComponentDeclarationsMap()));
Component Declaration: Lambda Execute Role
- Automatically grants access to all components in the project. For more fine-grained permissions control you can use the standard
iamRole
component. - Grants the ability to write to CloudWatch Logs.
this.lambdaRole = lambdaExecRole({ policies: [this.somePolicy] });
- Automatically grants access to all components in the project. For more fine-grained permissions control you can use the standard
Component Declaration: Lambda Function
this.func1 = lambdaFunction({ src: './func1', execRole: this.lambdaRole });
- The following file names are reserved by fsp. Do not include any files with these names in your function source directory.
fspLambdaProxyIndex.js
fspComponents.js
- The ability to customize the name of the lambda handler function is not available when using fsp. Your lambda handler should be exported from
index.js
with the function namelambdaHandler
.
- The following file names are reserved by fsp. Do not include any files with these names in your function source directory.
Component Declaration: HTTP Endpoint
this.myEndpoint = httpEndpoint({ method: 'POST', path: '/1234/5', handler: this.func1 });
Component Declaration: S3 Bucket
- Every fsp project is automatically given a
projectBucket
component. Reference it in your glue file usingthis.projectBucket
this.myBucket = bucket();
- Every fsp project is automatically given a
Component Declaration: Secret
this.mySecret = secret((cloudEnvironment) => { return cloudEnvironment.someSecretObjInYourCed; });
Component Declaration: Redis Cache
this.cache0 = redisCache({ cacheSubnetGroup: this.projectCacheSubnetGroup });
Referencing Components in Lambda Functions
Component Reference: Lambda Function
const { func1 } = require('./fspComponents.js'); module.exports.lambdaHandler = (event, context) => { // promise resolves after the lambda function has been started. await func1.launch({ arg1, arg2, arg3 }); // promise resolves with the lambda function's return value await func1.invoke({ arg1, arg2, arg3 }); // get a lambda function's maximum run time. const { Timeout } = (await func1.getAwsDescription()).Configuration }
Component Reference: Database
const { db0 } = require('./fspComponents.js'); module.exports.lambdaHandler = (event, context) => { const pgClient = pg.createClient(db0); }
Component Reference: Secret
const { mySecret } = require('./fspComponents.js'); module.exports.lambdaHandler = (event, context) => { // SecretString is already parsed for you const secretObj = mySecret; }
Component Reference: Redis Cache
const { cache0 } = require('./fspComponents.js'); const redis = require('redis'); module.exports.lambdaHandler = (event, context) => { const redisClient = redis.createClient(cache0); }
Undefined Component References
For all other component types (including custom types), the
externalIdentity
is exposed by./fspComponents.js
.const { myCustomComponent } = require('./fspComponents.js'); module.exports.lambdaHandler = (event, context) => { const { componentTypeName, /* ids returned by maker and updater */ } = myCustomComponent; }
Custom Component Types (CCT)
Fsp provides the essential component types that a serverless application needs. In many cases your application will rely on other services for which a component type does not exist.
- CCTs are declared using the
createComponentType
function. - CCTs must be declared inside of the glue.js file but outside of the glue function.
- CCTs should provide a
maker
for initialization of the resource, aupdater
for pushing configuration changes to the resource, and adestroyer
for tearing down the resource. A unqiuetypeName
must also be given. - For an exhaustive list of functions that a CCT can implement, see "/componentTypes/template.js".
Example:
addComponentType({
typeName: 'myComponentType',
maker: (identities, config) => {
const {
externalName // As a conveinence, fsp provides a UUID for you to use.
projectName, // The name of the fsp project.
cloudEnvironmentName, // <cloudEnvironmentName>Cloud.js
// Other identities that are availale in the maker phase:
componentIdentityDirectoryLocation, // { Bucket, Key }
internalName // componentName
} = identities;
// Create the resource.
// Return any identifers that you will need to update and delete the resource.
return { /* id: response.body.id */ };
// The following identifier keys are reserved by fsp, do not overwrite them:
// - componentTypeName
// If you are using the externalName that fsp provided, there is no need to return it because it is included automatically under the key "name". You can override this if you want.
},
return { /* did you change any ids? */ };
},
destroyer: (externalIdentity) {
const {
name, // externalName or the name you returned from maker
projectName, // The name of the fsp project.
cloudEnvironmentName, // <cloudEnvironmentName>Cloud.js
/* your ids */
} = externalIdentity;
// Destroy the resource.
}
});
module.exports = function() {}
CLI
To deploy your changes to AWS, use the
deploy
sub-command.fsp deploy -ce <cloud environment name>
To remove your product from AWS, use the
teardown
sub-command.fsp teardown -ce <cloud environment name>
To get your Component's ARNs, use the
identify
sub-command.fsp identify -ce <cloud environment name>
Planned Features
- Colorful output messages with emojis!
- More Concurrent IO.
- Component Types that represents the configuration of a database table.
- Store project version in project bucket. Ability to check what version of the project is running in a certain environment.