├── .gitignore ├── README.md ├── examples ├── awsm_lambda │ └── awsm.json └── awsm_root │ └── awsm.json ├── images ├── awsm_and_jaws.png └── awsm_logo.png └── registry.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.seed 2 | *.log 3 | *.csv 4 | *.dat 5 | *.out 6 | *.pid 7 | *.gz 8 | *.idea 9 | *.env 10 | 11 | **/.idea 12 | .DS_Store 13 | .tmp 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![AWSM logo aws modules lambda api gateway JAWS](images/awsm_logo.png) 2 | 3 | AWSM: Amazon Web Services Modules 4 | ================================= 5 | 6 | * **[Intro](https://github.com/awsm-org/awsm#intro)** 7 | * **[awsm.json](https://github.com/awsm-org/awsm#awsmjson)** 8 | * **[awsm.json At Module Root](https://github.com/awsm-org/awsm#awsmjson-at-module-root)** 9 | * **[awsm.json At Lambda Root](https://github.com/awsm-org/awsm#awsmjson-at-lambda-root)** 10 | * **[Lambda Configuration Options](https://github.com/awsm-org/awsm#lambda-configuration-options)** 11 | * **[Creating AWS-Modules](https://github.com/awsm-org/awsm#creating-aws-modules)** 12 | * **[Creating Reusable AWS-Modules](https://github.com/awsm-org/awsm#creating-re-usable-aws-modules)** 13 | * **[AWSM + NPM-Modules](https://github.com/awsm-org/awsm#awsm--npm-modules)** 14 | * **[Architecture](https://github.com/awsm-org/awsm#architecture)** 15 | * **[Workflow](https://github.com/awsm-org/awsm#workflow)** 16 | * **[Ideas & Themes](https://github.com/awsm-org/awsm#ideas--themes)** 17 | * **[Registry](https://github.com/awsm-org/awsm#registry)** 18 | 19 | ## Intro 20 | 21 | **Amazon Web Services Modules (aws-modules, awsm’s)** contain pre-written, isolated functions ready to run on one or multiple AWS Lambda functions. Some examples are: *functions that send out emails, register users or handle webhooks from other services*. 22 | 23 | The purpose of the *aws-module* format is to create an ecosystem of re-usable, standardized, optimized Lambda functions ready for deployment and easy installation into serverless projects. 24 | 25 | *aws-modules* were designed to work with [JAWS: The Serverless AWS Framework](https://github.com/jaws-framework/JAWS). 26 | The JAWS command line tool comes with commands to create and install *aws-modules* into your serverless projects. View the [JAWS documentation](https://github.com/jaws-framework/JAWS/tree/master/docs) for more information. 27 | 28 | *aws-modules* will soon support all of the languages AWS Lambda supports. Currently, only javascript (node.js) is supported. Building a module system that supports multiple programming languages is challenging, but since the functions of serverless projects/applications are completely isolated, functions written in different programming languages can be combined within the same project. Given some languages are more efficient for specific tasks, this is a nice benefit. 29 | 30 | ## awsm.json 31 | 32 | #### awsm.json At Module Root 33 | 34 | [Example of an `awsm.json` at the root of an aws-module](examples/awsm_root/awsm.json) 35 | 36 | The defining feature of an *aws-module* is an `awsm.json` file located at the root of the module. *aws-modules'* configuration settings, dependencies and authorship details are described in this `awsm.json` file. Below, are limited `awsm.json` examples. To view all available properties, see the [awsm.json file in this repo](./awsm.json). 37 | 38 | Any required AWS resources (e.g., DynamoDB, S3) **outside** of the Lambda and API Gateway resources your module requires in the "resources" object: 39 | 40 | ``` 41 | "name": "usersCreate", 42 | "description": "Creates a user", 43 | "version": "0.0.1", 44 | "location": "github.com/you/your_aws_modules_repo", 45 | "resources": { 46 | "cloudFormation": { 47 | "LambdaIamPolicyDocumentStatements": [], 48 | "ApiGatewayIamPolicyDocumentStatements": [], 49 | "Resources": {} 50 | } 51 | } 52 | ``` 53 | 54 | Please note that JAWS defines some standard [ AWS CloudFormation parameters](https://github.com/jaws-framework/JAWS/blob/master/docs/project_structure.md#resources-cfjson) that can be used as `"Ref"`'s 55 | 56 | #### awsm.json At Lambda Root 57 | 58 | [Example of an `awsm.json` at the root of a lambda sub-folder](examples/awsm_lambda/awsm.json) 59 | 60 | Within each resource/lambda directory is another **awsm.json** which describes either an AWS Lambda configuration, 61 | an API Gateway configuration, or both. `awsm.json` files within resource/action directories need only a "lambda" or 62 | "apiGateway" property (or both). 63 | 64 | ``` 65 | "lambda": { 66 | "enVars": [], 67 | "package": {}, 68 | "excludePatterns": {}, 69 | "cloudFormation": { 70 | "Description": "", 71 | "MemorySize": 1024, 72 | "Runtime": "nodejs", 73 | "Timeout": 6 74 | } 75 | }, 76 | "apiGateway": { 77 | "cloudFormation": {} 78 | } 79 | ``` 80 | 81 | 82 | #### Lambda Configuration Options 83 | 84 | **Note**: All of the attrs below assume the `lambda` attribute key prefix. 85 | 86 | * `envVars`: An array of environment variable names this project/module or lambda requires 87 | * `deploy`: if true, this app will be deployed the next time the `jaws deploy --tags` is run. See `deploy` command docs for more info. 88 | * `package`: How the code is packaged up into a zip file 89 | * `optimize`: How code is optimized for node runtimes, to improve lambda cold start time 90 | * `builder`: only `"browserify"` or `false` supported now. If `false` will just zip up entire `back` dir 91 | * `minify`: js minify or not 92 | * `ignore`: array of node modules to ignore. See [ignoring](https://github.com/substack/browserify-handbook#ignoring-and-excluding) 93 | * `exclude`: array of node modules to exclude. These modules will be loaded externally (from within zip or inside lambda). Note `aws-sdk` for node [can not be browserified](https://github.com/aws/aws-sdk-js/issues/696). See [ignoring](https://github.com/substack/browserify-handbook#ignoring-and-excluding) 94 | * `includePaths`: Paths rel to back (dirs or files) to be included in zip. Paths included after optimization step. 95 | * `excludePatterns`: Array of regular expressions rel to back. Removed before optimization step. If not optimizing, everything in back dir will be included in zip. Use this to exclude stuff you don't want in your zip. Strings will be passed to `new RegExp()` 96 | * `cloudFormation` 97 | * `Handler,MemorySize,Runtime,Timeout`: can all be found in the [aws docs](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html) 98 | * We recommend 1024 memory to improve cold/warm start times. `handler` is relative to back dir 99 | 100 | 101 | ## Creating AWS-Modules 102 | 103 | Whether you are writing aws-modules exclusively for your serverless project (every Lambda function in a JAWS project is an aws-module) or writing them for sharing publicly, the process to create them is the same. 104 | 105 | * Install the JAWS command line tool via npm, which you will use to generate scaffolding for new aws-modules: 106 | 107 | $ npm install jaws-framework -g 108 | 109 | * Create a new JAWS project: 110 | 111 | $ jaws project create 112 | 113 | * Create a new aws-module. Enter a module name and the name of the first Lambda function your aws-module will use. For example, your module name could be `awsm-images` and the first Lambda function your module offers is the ability to re-size images, enter the following: 114 | 115 | $ jaws module create awsm-images resize 116 | 117 | * Scaffolding should now be available in your project’s `aws_modules` folder. 118 | 119 | ## Creating Re-Usable AWS-Modules 120 | 121 | If you want to use your aws-module across multiple projects and optionally share it with the aws-module community, do the following: 122 | 123 | * aws-modules rely on different package managers for delivery/installation. Choose the package manager that corresponds with the runtime of the Lambda functions within your module and create a corresponding package. Currently, only the nodejs runtime is supported by aws-modules. Therefore, run `npm init` within the root of your aws-module to make your aws-module an npm-module and edit the `package.json` with your authorship information in your module’s root. 124 | 125 | * Publish your aws-module to the respective package manager’s registry. For npm-modules, run `npm publish`. 126 | 127 | * Fill in your authorship details in your aws-module’s root awsm.json file. Sorry for the redundancy, but we will be unveiling a separate awsm registry which will assist in search and discovery of aws-modules across all programming languages/AWS Lambda runtimes. 128 | 129 | #### AWSM + NPM-Modules 130 | 131 | ##### Architecture 132 | 133 | awsm npm modules should have the following structure. Upon `npm install yourmodule`, JAWS will copy contents of the `awsm` folder into the serverless project's `aws_modules` folder on the npm *postinstall* hook. 134 | 135 | ``` 136 | module 137 | awsm.json 138 | package.json 139 | awsm 140 | lambda1 141 | awsm.json 142 | handler.js 143 | index.js 144 | event.json 145 | lib 146 | modularcode.js 147 | ``` 148 | 149 | ###### `/awsm.json` 150 | This contains module and authorship information for publishing your awsm on the upcoming aws-module registry. 151 | ###### `/package.json` 152 | This contains module and authorship information for publishing your awsm as an npm module on their registry. Remember, awsm's use different package managers for delivery. 153 | ###### `/awsm/` 154 | This contains starter scaffolding for lambda functions and endpoints. When someone installs your awsm via npm, the contents of this folder will be copied to their *aws_modules* folder, while the rest of your awsm will reside in their project's *node_modules* folder. As a best practice, don't put a lot of code in the scaffolding. Instead, focus on making your code modular and re-usable by putting the bulk of it in `lib/yourcode.js`. 155 | ###### `/awsm/lambda1` 156 | Your awsm can have one or multiple lambda functions. Each lambda function resides in a sub-folder like this. 157 | ###### `/awsm/lambda1/awsm.json` 158 | This contains configuration settings for this lambda and/or a URL endpoint that will be created via API Gateway. Lambda and API Gateway config information is stored in AWS CloudFormation syntax. 159 | ###### `/awsm/lambda1/hander.js` 160 | This contains the handler which AWS Lambda will call. As a best practice, don't put your logic in here. Keep it separate so that it is re-usable, testable, and AWS independent. 161 | ###### `/awsm/lambda1/index.js` 162 | This is your lambda's code, kept separate to be re-usable across modules, testable, and AWS independent. Please note that all of the dependencies in your awsm's package.json can only be required in code that is in `/lib/`. Do not require those dependencies in this `index.js` file or the `handler.js` file. 163 | ###### `/awsm/lambda1/event.json` 164 | This is sample event information which you can use to test your Lambda function locally. 165 | ###### `/lib/` 166 | When your awsm npm module is installed via JAWS, everything in the *awsm* folder will be copied to the project's *aws_modules* folder, but everything in this *lib* folder will be kept within the project's *node_modules* folder. Generally, code that should not be modified and code that needs to be required across all aws_modules in a serverless project should be put in this folder. Code that will be modified should be put in the `awsm` folder. 167 | ###### `/lib/modularcode.js` 168 | This is code that should not be modified (like a normal npm module) and can be shared/required across all aws_modules in a serverless project. Please note that all dependencies that are in your awsm's package.json can only be required in code that is located in the `lib` folder. 169 | 170 | ##### Workflow 171 | 172 | While you develop your module locally, it's useful to have a project to implement and test it in. With the following steps, you can install the module in your project, after which it can be tested. 173 | 174 | * Switch to the project in which you want to install your NPM module. 175 | 176 | * Run `npm link ` to create a link in your project's `/node_modules` directory to the globally-installed link. 177 | 178 | * Run `jaws postinstall npm` to execute the `postinstall` command (since `npm link` skips the `postinstall` script). 179 | 180 | Now your module is installed! 181 | 182 | Please note that the module is not yet published to the NPM registry and therefore not yet added to your project's package.json. Read more about this in the NPM documentation on [publishing NPM packages](https://docs.npmjs.com/getting-started/publishing-npm-packages). 183 | 184 | ## Ideas & Themes 185 | 186 | So many things can be aws-modules. Here are a few popular themes for inspiration: 187 | 188 | * **Users/Sessions CRUD** - Bonus if you include sign on via popular 3rd party services (e.g., Github) 189 | * **Analytics/Event Functions** - Captures common user events 190 | * **Image functions** - Resize, filters, etc. 191 | * **Email - Transactional** email functions (e.g., receipt, welcome, where you been?) 192 | * **Email - Marketing** - Blasting html emails to many addresses for dirt cheap via Lambda + SES 193 | * **Stripe Webhook Handlers** 194 | * **Slack Webhook handlers** 195 | * **Webhook handlers for all the things** 196 | * **Twilio functions** - Send SMS 197 | * **3rd Party Authentication Handlers** - Pre-built authentication with the most popular peeps. 198 | * **Proxy Modules** - API Gateway has the ability to be a proxy for other endpoints and do request and response transforms without ever needing lambda. This presents an opportunity for people to make their own API endpoints that mask other API endpoints and publish those as aws-modules. For example, you can mask a Slack API endpoint with api.yourapp.com/slack/post_message and define how the response from Slack should be transformed in your awsm.apiGateway.cloudFormation template and publish that as a module for others to reuse. 199 | 200 | ## Registry 201 | 202 | Want to tell the world about your aws module? Send a pull request against [registry.json](./registry.json). This poor mans registry is just a temporary solution. 203 | 204 | -------------------------------------------------------------------------------- /examples/awsm_lambda/awsm.json: -------------------------------------------------------------------------------- 1 | /* 2 | * awsm.json 3 | * - This file shows ALL properties available for awsm.json files located at the root of a lambda subfolder 4 | */ 5 | 6 | { 7 | "lambda": { 8 | "envVars": ["string"], 9 | "package": { 10 | "optimize": { 11 | "builder": "browserify", 12 | "minify": true, 13 | "ignore": [], 14 | "exclude": [ 15 | "aws-sdk" 16 | ], 17 | "includePaths": [] 18 | }, 19 | "excludePatterns": [ 20 | "lambdas/[u].*", 21 | "lambdas/bundle/b.*" 22 | ] 23 | }, 24 | "cloudFormation": { 25 | "Description": "lambda function description", 26 | "Handler": "aws_modules/resource/action/handler.handler", 27 | "MemorySize": 1024, 28 | "Runtime": "nodejs", 29 | "Timeout": 10 30 | } 31 | }, 32 | "apiGateway": { 33 | "cloudFormation": { 34 | "Type": "AWS", 35 | "Path": "resource/action", 36 | "Method": "POST", 37 | "AuthorizationType": "none", 38 | "ApiKeyRequired": false, 39 | "RequestTemplates": { 40 | "application/json": "{\"access_token\":\"$input.params('access_token')\",\"body\":\"$input.json('$')\"}" 41 | }, 42 | "RequestParameters": { 43 | "integration.request.querystring.integrationQueryParam": "method.request.querystring.access_token" 44 | }, 45 | "CacheNamespace": "String", 46 | "CacheKeyParameters": [], 47 | "Responses": { 48 | "default": { 49 | "statusCode": "200", 50 | "responseParameters": { 51 | "method.response.header.test-method-response-header": "integration.response.header.integrationResponseHeaderParam1" 52 | }, 53 | "responseTemplates": { 54 | "application/json": {} 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /examples/awsm_root/awsm.json: -------------------------------------------------------------------------------- 1 | /* 2 | * awsm.json 3 | * - This file shows ALL properties available for awsm.json files located at the root of an aws_module 4 | */ 5 | 6 | { 7 | "name": "moduleName", 8 | "description": "A description of your aws-module", 9 | "version": "0.0.1", 10 | "location": "github url to your module's repo", 11 | "lambda": { 12 | "envVars": ["string"], 13 | "package": { 14 | "optimize": { 15 | "builder": "browserify", 16 | "minify": true, 17 | "ignore": [], 18 | "exclude": [ 19 | "aws-sdk" 20 | ], 21 | "includePaths": [] 22 | } 23 | }, 24 | "excludePatterns": [ 25 | "lambdas/[u].*", 26 | "lambdas/bundle/b.*" 27 | ], 28 | "cloudFormation": { 29 | "Description": "lambda function description", 30 | "Handler": "aws_modules/resource/action/handler.handler", 31 | "MemorySize": 1024, 32 | "Runtime": "nodejs", 33 | "Timeout": 10 34 | } 35 | }, 36 | "apiGateway": { 37 | "cloudFormation": { 38 | "Type": "AWS", 39 | "Path": "resource/action", 40 | "Method": "POST", 41 | "AuthorizationType": "none", 42 | "ApiKeyRequired": false, 43 | "RequestTemplates": { 44 | "application/json": "{\"access_token\":\"$input.params('access_token')\",\"body\":\"$input.json('$')\"}" 45 | }, 46 | "RequestParameters": { 47 | "integration.request.querystring.integrationQueryParam": "method.request.querystring.access_token" 48 | }, 49 | "CacheNamespace": "String", 50 | "CacheKeyParameters": [], 51 | "Responses": { 52 | "default": { 53 | "statusCode": "200", 54 | "responseParameters": { 55 | "method.response.header.test-method-response-header": "integration.response.header.integrationResponseHeaderParam1" 56 | }, 57 | "responseTemplates": { 58 | "application/json": {} 59 | } 60 | } 61 | } 62 | } 63 | }, 64 | "resources": { 65 | "cloudFormation": { 66 | "LambdaIamPolicyDocumentStatements": [], 67 | "ApiGatewayIamPolicyDocumentStatements": [], 68 | "Resources": {} 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /images/awsm_and_jaws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsm-org/awsm/be92c16db86fbba34b6f08851b5867e4fee5c744/images/awsm_and_jaws.png -------------------------------------------------------------------------------- /images/awsm_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awsm-org/awsm/be92c16db86fbba34b6f08851b5867e4fee5c744/images/awsm_logo.png -------------------------------------------------------------------------------- /registry.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"awsm-images", 4 | "url":"https://github.com/awsm-org/awsm-images", 5 | "description":"awsm refrence implementation. Creates REST API routes for image modifications. This exercises many of the aws-module configurations. It also showcases how to browserify your lambda code and still include a non-optimized ver of aws-sdk." 6 | }, 7 | { 8 | "name":"awsm-users", 9 | "url":"https://github.com/dekz/awsm-users", 10 | "description":"Creates REST API routes for User creation and authentication for your application via DynamoDB" 11 | }, 12 | { 13 | "name":"awsm-cloudfront", 14 | "url":"https://github.com/boushley/awsm-cloudfront", 15 | "description":"This allows for hosting a web application entirely using JAWS. Puts an AWS Cloudfront distribution in front of a static S3 bucket and API Gateway endpoints all on the same domain to avoid any same origin problems. No need for CORS!" 16 | }, 17 | { 18 | "name":"awsm-middleware", 19 | "url":"https://github.com/jwulf/awsm-middleware", 20 | "description":"Middleware for your JAWS project, based on segment.io" 21 | }, 22 | { 23 | "name":"awsm-loggly", 24 | "url":"https://github.com/jwulf/awsm-loggly", 25 | "description":"An awsm that has no lambdas but instead exports code you can use to send logging to Loggly from your lambdas. Allows you to trace application execution across multiple lambdas and debug your application flow." 26 | }, 27 | { 28 | "name":"awsm-twilio", 29 | "url":"https://github.com/eahefnawy/awsm-twilio", 30 | "description":"JAWS package/Lambda func. to send SMS via Twilio." 31 | }, 32 | { 33 | "name":"awsm-stripe-webhook ", 34 | "url":"https://github.com/eahefnawy/awsm-stripe-webhook", 35 | "description":"JAWS package/API endpint/Webhook for your stripe notifications" 36 | }, 37 | { 38 | "name":"awsm-slack-webhook", 39 | "url":"https://github.com/eahefnawy/awsm-slack-webhook", 40 | "description":"JAWS package/API endpint/Webhook for Slack" 41 | }, 42 | { 43 | "name":"awsm-mailer", 44 | "url":"https://github.com/eahefnawy/awsm-mailer", 45 | "description":"AWSM package for sending emails." 46 | }, 47 | { 48 | "name":"awsm-s3tokenvendor", 49 | "url":"https://github.com/binoculars/awsm-s3tokenvendor", 50 | "description":"AWS Module to generate S3 upload tokens" 51 | } 52 | ] 53 | --------------------------------------------------------------------------------