From 28e5f0822f54e7ea4814d1c7b595401b41f62a45 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 11:06:19 -0500 Subject: [PATCH 01/18] Extract the app router --- demo-app.js | 7 ++++--- demo-router.js | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 demo-router.js diff --git a/demo-app.js b/demo-app.js index 59f5040..b2b8f07 100644 --- a/demo-app.js +++ b/demo-app.js @@ -1,11 +1,12 @@ var Server = require('./server'); +var Router = require('./demo-router'); + var util = require('util'); var server = new Server(); +var router = new Router(); -server.routes(function() { - this.get('/posts', {from: 'demo-app-posts', with: 'index'}); -}); +router.loadRoutes(server); server.start(3000); diff --git a/demo-router.js b/demo-router.js new file mode 100644 index 0000000..cbca409 --- /dev/null +++ b/demo-router.js @@ -0,0 +1,13 @@ +function Router() { + +} + +Router.prototype.loadRoutes = function(server){ + + server.routes(function() { + this.get('/posts', {from: 'demo-app-posts', with: 'index'}); + }); + +} + +module.exports = Router; From 1b2ebda76fe6ad98f89c7bdc2206d208d01986eb Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 11:16:37 -0500 Subject: [PATCH 02/18] Refactor post endpoint to follow express style --- demo-app-posts.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/demo-app-posts.js b/demo-app-posts.js index 2462e0d..8b68f29 100644 --- a/demo-app-posts.js +++ b/demo-app-posts.js @@ -1,5 +1,6 @@ module.exports = { index: function(req, res) { - return [200, {}, "ohai"]; + res.status(200); + res.json({ message: "ohai"}); } -}; \ No newline at end of file +}; From 87f84767ada998be5d0bfe6a4dea348634393b2c Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 12:22:02 -0500 Subject: [PATCH 03/18] Add a demo lambda handler and a runner for testing it locally --- demo-app-posts-lambda-handler.js | 9 ++ demo-app-posts-lambda-runner.js | 17 ++++ lambda-utils.js | 156 +++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 demo-app-posts-lambda-handler.js create mode 100644 demo-app-posts-lambda-runner.js create mode 100644 lambda-utils.js diff --git a/demo-app-posts-lambda-handler.js b/demo-app-posts-lambda-handler.js new file mode 100644 index 0000000..0f36723 --- /dev/null +++ b/demo-app-posts-lambda-handler.js @@ -0,0 +1,9 @@ +const lambdaUtils = require('./lambda-utils'); + +const endpointLogic = require('./demo-app-posts'); + +module.exports.handler = function(event, context, cb) { + var req = lambdaUtils.buildRequest(event,context,cb); + var res = lambdaUtils.buildResponse(event,context,cb); + endpointLogic.index(req, res); +}; diff --git a/demo-app-posts-lambda-runner.js b/demo-app-posts-lambda-runner.js new file mode 100644 index 0000000..0ce812d --- /dev/null +++ b/demo-app-posts-lambda-runner.js @@ -0,0 +1,17 @@ +const lambdaHandler = require('./demo-app-posts-lambda-handler'); + +var event = { + headers: {} +}; +var context = {}; +function cb(error, data){ + if(error){ + console.log("got error-------"); + console.log(error); + return; + } + console.log("got data-------"); + console.log(data); +} + +lambdaHandler.handler(event, context, cb); diff --git a/lambda-utils.js b/lambda-utils.js new file mode 100644 index 0000000..fa0151f --- /dev/null +++ b/lambda-utils.js @@ -0,0 +1,156 @@ +module.exports.buildRequest = function(event, context, cb) { + var req = {}; + + // http://expressjs.com/en/api.html#req + // Properties + req.app = null; // Not sure this applies in our context... + req.baseUrl = event.baseUrl; + req.body = event.body; + req.cookies = {}; // TODO : Figure out how to get cookies from AWS Gateway + req.fresh = true; // TODO : Does this apply in our context? + req.hostname = event.headers.Host; + //req.ip = event.headers["X-Forwarded-For"].split(", ")[0]; + req.ips = event.headers["X-Forwarded-For"]; + req.method = event.method; + req.originalUrl = ""; // TODO : Figrure out how to reconstruct this + req.params = event.params; + req.path = event.baseUrl; // TODO : This isn't quite right... + req.protocol = event.headers["X-Forwarded-Proto"]; + req.query = event.query; + req.route = null; // TODO : Does this apply to us? + req.secure = req.protocol === 'https'; + req.signedCookies = {}; // TODO : ??? + req.stale = false; // TODO : Does this apply in our context? + req.subdomains = []; // TODO: Does this apply? + req.xhr = event.headers["X-Requested-With"] === 'XMLHttpRequest'; + + // Methods + /* + var accept = realAccepts(req); + req.accepts = function accepts(types){ + // TODO : Fix me! + return types; + //return accept.type(types); + }; + */ + req.acceptsCharsets = function acceptsCharsets(){ + // TODO : Fix me! + }; + + req.acceptsEncodings = function acceptsEncodings(){ + // TODO : Fix me! + }; + + req.acceptsLanguages = function acceptsLanguages(){ + // TODO : Fix me! + }; + + req.get = function get(field){ + return event.headers[field]; + } + + req.is = function is(type){ + // TODO: Fix me! + } + + return req; +} + +module.exports.buildResponse = function(event, context, cb) { + var res = {}; + + // Properties + res.app = null; // TODO : Does this apply? + res.headersSent = false; // TODO : Is this right? + res.locals = {}; // TODO: Does this apply? + + res.headers = []; + + // Methods + res.append = function append(field,value){ + res.headers.push([field,value]); + } + + res.attachment = function attachment(){ + // TODO: Can we return attachments through API Gatewway? + } + + res.cookie = function cookie(name, value, options){ + // TODO: Can we set cookies? + } + + res.clearCookie = function clearCookie(name, options){ + // TODO: Can we set cookies? + } + + res.download = function download(){ + // TODO: Can we do this? + } + + res.end = function end(){ + // TODO: Implement me! + } + + res.format = function format(){ + // TODO: does this apply? + } + + res.get = function get(field){ + return headers[field]; + } + + res.json = function json(payload){ + cb(null, payload); + } + + res.jsonp = function jsonp(){ + // TODO: Do we need to support josnp? + } + + res.links = function links(){ + // TODO: Implement me! + } + + res.location = function location(){ + // TODO: Implement me! + } + + res.redirect = function redirect(){ + // TODO: Implement me! + } + + res.render = function render(){ + // TODO: Does this apply? + } + + res.send = function send(){ + // TODO: Does this apply? + } + + res.sendFile = function sendFile(){ + // TODO: Does this apply? + } + + res.sendStatus = function sendStatus(){ + // TODO: Implement me! + } + + res.set = function set(){ + // TODO: Implement me! + } + + res.status = function status(){ + // TODO: Implement me! + } + + res.type = function type(){ + // TODO: Implement me! + } + + res.vary = function vary(){ + // TODO: Implement me! + } + + return res; +} + From f3dc126f75452563c0d54cde0d629bc7ccf8535d Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 12:30:22 -0500 Subject: [PATCH 04/18] Revert "Extract the app router" This reverts commit 28e5f0822f54e7ea4814d1c7b595401b41f62a45. --- demo-app.js | 7 +++---- demo-router.js | 13 ------------- 2 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 demo-router.js diff --git a/demo-app.js b/demo-app.js index b2b8f07..59f5040 100644 --- a/demo-app.js +++ b/demo-app.js @@ -1,12 +1,11 @@ var Server = require('./server'); -var Router = require('./demo-router'); - var util = require('util'); var server = new Server(); -var router = new Router(); -router.loadRoutes(server); +server.routes(function() { + this.get('/posts', {from: 'demo-app-posts', with: 'index'}); +}); server.start(3000); diff --git a/demo-router.js b/demo-router.js deleted file mode 100644 index cbca409..0000000 --- a/demo-router.js +++ /dev/null @@ -1,13 +0,0 @@ -function Router() { - -} - -Router.prototype.loadRoutes = function(server){ - - server.routes(function() { - this.get('/posts', {from: 'demo-app-posts', with: 'index'}); - }); - -} - -module.exports = Router; From 1d5daca7a7ffe1175d225f6e7462426a8ff9f714 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 14:37:07 -0500 Subject: [PATCH 05/18] Add a serverless directory (sls project create) --- _serverless/.gitignore | 43 ++++++++++++++++++++++ _serverless/package.json | 13 +++++++ _serverless/s-project.json | 5 +++ _serverless/s-resources-cf.json | 64 +++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 _serverless/.gitignore create mode 100644 _serverless/package.json create mode 100644 _serverless/s-project.json create mode 100644 _serverless/s-resources-cf.json diff --git a/_serverless/.gitignore b/_serverless/.gitignore new file mode 100644 index 0000000..7af0b6e --- /dev/null +++ b/_serverless/.gitignore @@ -0,0 +1,43 @@ +# Logs +logs +*.log +npm-debug.log + +# Runtime data +pids +*.pid +*.seed +dist + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules + +#IDE +**/.idea + +#OS +.DS_Store +.tmp + +#SERVERLESS +admin.env +.env + +#Ignore _meta folder +_meta \ No newline at end of file diff --git a/_serverless/package.json b/_serverless/package.json new file mode 100644 index 0000000..e6a3fd9 --- /dev/null +++ b/_serverless/package.json @@ -0,0 +1,13 @@ +{ + "name": "demo-app", + "version": "0.0.1", + "description": "A Serverless Project and its Serverless Plugin dependencies.", + "author": "me", + "license": "MIT", + "private": false, + "repository": { + "type": "git", + "url": "git://github.com/" + }, + "dependencies": {} +} \ No newline at end of file diff --git a/_serverless/s-project.json b/_serverless/s-project.json new file mode 100644 index 0000000..a4dc70b --- /dev/null +++ b/_serverless/s-project.json @@ -0,0 +1,5 @@ +{ + "name": "demo-app", + "custom": {}, + "plugins": [] +} \ No newline at end of file diff --git a/_serverless/s-resources-cf.json b/_serverless/s-resources-cf.json new file mode 100644 index 0000000..8b5cd2d --- /dev/null +++ b/_serverless/s-resources-cf.json @@ -0,0 +1,64 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway", + "Resources": { + "IamRoleLambda": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com" + ] + }, + "Action": [ + "sts:AssumeRole" + ] + } + ] + }, + "Path": "/" + } + }, + "IamPolicyLambda": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "${stage}-${project}-lambda", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Resource": "arn:aws:logs:${region}:*:*" + } + ] + }, + "Roles": [ + { + "Ref": "IamRoleLambda" + } + ] + } + } + }, + "Outputs": { + "IamRoleArnLambda": { + "Description": "ARN of the lambda IAM role", + "Value": { + "Fn::GetAtt": [ + "IamRoleLambda", + "Arn" + ] + } + } + } +} \ No newline at end of file From e8a1850e5640833ef47fc3fb684b7cb60e8a046b Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 14:48:43 -0500 Subject: [PATCH 06/18] Update lambda utils to match the pass through request template --- lambda-utils.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lambda-utils.js b/lambda-utils.js index fa0151f..e9ce029 100644 --- a/lambda-utils.js +++ b/lambda-utils.js @@ -8,21 +8,21 @@ module.exports.buildRequest = function(event, context, cb) { req.body = event.body; req.cookies = {}; // TODO : Figure out how to get cookies from AWS Gateway req.fresh = true; // TODO : Does this apply in our context? - req.hostname = event.headers.Host; - //req.ip = event.headers["X-Forwarded-For"].split(", ")[0]; - req.ips = event.headers["X-Forwarded-For"]; + req.hostname = event.params.header.Host; + //req.ip = event.params.header["X-Forwarded-For"].split(", ")[0]; + req.ips = event.params.header["X-Forwarded-For"]; req.method = event.method; req.originalUrl = ""; // TODO : Figrure out how to reconstruct this req.params = event.params; req.path = event.baseUrl; // TODO : This isn't quite right... - req.protocol = event.headers["X-Forwarded-Proto"]; + req.protocol = event.params.header["X-Forwarded-Proto"]; req.query = event.query; req.route = null; // TODO : Does this apply to us? req.secure = req.protocol === 'https'; req.signedCookies = {}; // TODO : ??? req.stale = false; // TODO : Does this apply in our context? req.subdomains = []; // TODO: Does this apply? - req.xhr = event.headers["X-Requested-With"] === 'XMLHttpRequest'; + req.xhr = event.params.header["X-Requested-With"] === 'XMLHttpRequest'; // Methods /* @@ -46,7 +46,7 @@ module.exports.buildRequest = function(event, context, cb) { }; req.get = function get(field){ - return event.headers[field]; + return event.params.header[field]; } req.is = function is(type){ From 07c0ec3cb6cb7e888cc86fe05d0186229fff1a7b Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 14:52:00 -0500 Subject: [PATCH 07/18] Add some templates for serverless files --- serverless-templates/handler.js | 12 ++++ serverless-templates/s-function.json | 51 +++++++++++++++ serverless-templates/s-templates.yaml | 93 +++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 serverless-templates/handler.js create mode 100644 serverless-templates/s-function.json create mode 100644 serverless-templates/s-templates.yaml diff --git a/serverless-templates/handler.js b/serverless-templates/handler.js new file mode 100644 index 0000000..bba5e78 --- /dev/null +++ b/serverless-templates/handler.js @@ -0,0 +1,12 @@ +const lambdaUtils = require('./lambda-utils'); + +const endpointLogic = require('./endpoint-logic'); + +module.exports.handler = function(event, context, cb) { + console.log('got event'); + console.log(JSON.stringify(event,null,'\t')); + var req = lambdaUtils.buildRequest(event,context,cb); + var res = lambdaUtils.buildResponse(event,context,cb); + endpointLogic.index(req, res); +}; + diff --git a/serverless-templates/s-function.json b/serverless-templates/s-function.json new file mode 100644 index 0000000..ecf61c4 --- /dev/null +++ b/serverless-templates/s-function.json @@ -0,0 +1,51 @@ +{ + "name": "demo-app-posts", + "runtime": "nodejs4.3", + "description": "Serverless Lambda function for project: demo-app", + "customName": false, + "customRole": false, + "handler": "handler.handler", + "timeout": 6, + "memorySize": 1024, + "authorizer": {}, + "custom": { + "excludePatterns": [] + }, + "endpoints": [ + { + "path": "demo-app-posts", + "method": "GET", + "type": "AWS", + "authorizationType": "none", + "authorizerFunction": false, + "apiKeyRequired": false, + "requestParameters": {}, + "requestTemplates": "$${passthroughTemplate}", + "responses": { + "400": { + "statusCode": "400" + }, + "default": { + "statusCode": "200", + "responseParameters": {}, + "responseModels": { + "application/json;charset=UTF-8": "Empty" + }, + "responseTemplates": { + "application/json;charset=UTF-8": "" + } + } + } + } + ], + "events": [], + "environment": { + "SERVERLESS_PROJECT": "${project}", + "SERVERLESS_STAGE": "${stage}", + "SERVERLESS_REGION": "${region}" + }, + "vpc": { + "securityGroupIds": [], + "subnetIds": [] + } +} diff --git a/serverless-templates/s-templates.yaml b/serverless-templates/s-templates.yaml new file mode 100644 index 0000000..de5912b --- /dev/null +++ b/serverless-templates/s-templates.yaml @@ -0,0 +1,93 @@ +passthroughTemplate: + application/json: | + ## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html + ## This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload + #set($allParams = $input.params()) + { + "body-json" : "$input.json('$')", + "params" : { + #foreach($type in $allParams.keySet()) + #set($params = $allParams.get($type)) + "$type" : { + #foreach($paramName in $params.keySet()) + "$paramName" : "$util.escapeJavaScript($params.get($paramName))" + #if($foreach.hasNext),#end + #end + } + #if($foreach.hasNext),#end + #end + }, + "stage-variables" : { + #foreach($key in $stageVariables.keySet()) + "$key" : "$util.escapeJavaScript($stageVariables.get($key))" + #if($foreach.hasNext),#end + #end + }, + "context" : { + "account-id" : "$context.identity.accountId", + "api-id" : "$context.apiId", + "api-key" : "$context.identity.apiKey", + "authorizer-principal-id" : "$context.authorizer.principalId", + "caller" : "$context.identity.caller", + "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider", + "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType", + "cognito-identity-id" : "$context.identity.cognitoIdentityId", + "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId", + "http-method" : "$context.httpMethod", + "stage" : "$context.stage", + "source-ip" : "$context.identity.sourceIp", + "user" : "$context.identity.user", + "user-agent" : "$context.identity.userAgent", + "user-arn" : "$context.identity.userArn", + "request-id" : "$context.requestId", + "resource-id" : "$context.resourceId", + "resource-path" : "$context.resourcePath" + } + } +expressRequestTemplate: + application/json: | + { + "body": "$input.json('$')", + "headers": { + #foreach($header in $input.params().header.keySet()) + "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end + #end + }, + "method": "$context.httpMethod", + "params": { + #foreach($param in $input.params().path.keySet()) + "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end + #end + }, + "query": { + #foreach($queryParam in $input.params().querystring.keySet()) + "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end + #end + }, + "baseUrl": "$context.resourcePath", + "context": { + #foreach($contextItem in $context.keySet()) + "$contextItem": "$util.escapeJavaScript($context.get($contextItem))" #if($foreach.hasNext),#end + #end + } + } +fullRequestTemplate: + application/json: | + $input.json('$'), + "headers": { + #foreach($header in $input.params().header.keySet()) + "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end + #end + }, + "method": "$context.httpMethod", + "params": { + #foreach($param in $input.params().path.keySet()) + "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end + #end + }, + "query": { + #foreach($queryParam in $input.params().querystring.keySet()) + "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end + #end + } + } From 4faafd46e727d8918736698d920e28374dab4291 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 14:52:20 -0500 Subject: [PATCH 08/18] serverless function for demo-app-posts --- _serverless/demo-app-posts/endpoint-logic.js | 6 + _serverless/demo-app-posts/event.json | 1 + _serverless/demo-app-posts/handler.js | 12 ++ _serverless/demo-app-posts/lambda-utils.js | 156 +++++++++++++++++++ _serverless/demo-app-posts/s-function.json | 51 ++++++ _serverless/demo-app-posts/s-templates.yaml | 93 +++++++++++ 6 files changed, 319 insertions(+) create mode 100644 _serverless/demo-app-posts/endpoint-logic.js create mode 100644 _serverless/demo-app-posts/event.json create mode 100644 _serverless/demo-app-posts/handler.js create mode 100644 _serverless/demo-app-posts/lambda-utils.js create mode 100644 _serverless/demo-app-posts/s-function.json create mode 100644 _serverless/demo-app-posts/s-templates.yaml diff --git a/_serverless/demo-app-posts/endpoint-logic.js b/_serverless/demo-app-posts/endpoint-logic.js new file mode 100644 index 0000000..8b68f29 --- /dev/null +++ b/_serverless/demo-app-posts/endpoint-logic.js @@ -0,0 +1,6 @@ +module.exports = { + index: function(req, res) { + res.status(200); + res.json({ message: "ohai"}); + } +}; diff --git a/_serverless/demo-app-posts/event.json b/_serverless/demo-app-posts/event.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/_serverless/demo-app-posts/event.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/_serverless/demo-app-posts/handler.js b/_serverless/demo-app-posts/handler.js new file mode 100644 index 0000000..bba5e78 --- /dev/null +++ b/_serverless/demo-app-posts/handler.js @@ -0,0 +1,12 @@ +const lambdaUtils = require('./lambda-utils'); + +const endpointLogic = require('./endpoint-logic'); + +module.exports.handler = function(event, context, cb) { + console.log('got event'); + console.log(JSON.stringify(event,null,'\t')); + var req = lambdaUtils.buildRequest(event,context,cb); + var res = lambdaUtils.buildResponse(event,context,cb); + endpointLogic.index(req, res); +}; + diff --git a/_serverless/demo-app-posts/lambda-utils.js b/_serverless/demo-app-posts/lambda-utils.js new file mode 100644 index 0000000..e9ce029 --- /dev/null +++ b/_serverless/demo-app-posts/lambda-utils.js @@ -0,0 +1,156 @@ +module.exports.buildRequest = function(event, context, cb) { + var req = {}; + + // http://expressjs.com/en/api.html#req + // Properties + req.app = null; // Not sure this applies in our context... + req.baseUrl = event.baseUrl; + req.body = event.body; + req.cookies = {}; // TODO : Figure out how to get cookies from AWS Gateway + req.fresh = true; // TODO : Does this apply in our context? + req.hostname = event.params.header.Host; + //req.ip = event.params.header["X-Forwarded-For"].split(", ")[0]; + req.ips = event.params.header["X-Forwarded-For"]; + req.method = event.method; + req.originalUrl = ""; // TODO : Figrure out how to reconstruct this + req.params = event.params; + req.path = event.baseUrl; // TODO : This isn't quite right... + req.protocol = event.params.header["X-Forwarded-Proto"]; + req.query = event.query; + req.route = null; // TODO : Does this apply to us? + req.secure = req.protocol === 'https'; + req.signedCookies = {}; // TODO : ??? + req.stale = false; // TODO : Does this apply in our context? + req.subdomains = []; // TODO: Does this apply? + req.xhr = event.params.header["X-Requested-With"] === 'XMLHttpRequest'; + + // Methods + /* + var accept = realAccepts(req); + req.accepts = function accepts(types){ + // TODO : Fix me! + return types; + //return accept.type(types); + }; + */ + req.acceptsCharsets = function acceptsCharsets(){ + // TODO : Fix me! + }; + + req.acceptsEncodings = function acceptsEncodings(){ + // TODO : Fix me! + }; + + req.acceptsLanguages = function acceptsLanguages(){ + // TODO : Fix me! + }; + + req.get = function get(field){ + return event.params.header[field]; + } + + req.is = function is(type){ + // TODO: Fix me! + } + + return req; +} + +module.exports.buildResponse = function(event, context, cb) { + var res = {}; + + // Properties + res.app = null; // TODO : Does this apply? + res.headersSent = false; // TODO : Is this right? + res.locals = {}; // TODO: Does this apply? + + res.headers = []; + + // Methods + res.append = function append(field,value){ + res.headers.push([field,value]); + } + + res.attachment = function attachment(){ + // TODO: Can we return attachments through API Gatewway? + } + + res.cookie = function cookie(name, value, options){ + // TODO: Can we set cookies? + } + + res.clearCookie = function clearCookie(name, options){ + // TODO: Can we set cookies? + } + + res.download = function download(){ + // TODO: Can we do this? + } + + res.end = function end(){ + // TODO: Implement me! + } + + res.format = function format(){ + // TODO: does this apply? + } + + res.get = function get(field){ + return headers[field]; + } + + res.json = function json(payload){ + cb(null, payload); + } + + res.jsonp = function jsonp(){ + // TODO: Do we need to support josnp? + } + + res.links = function links(){ + // TODO: Implement me! + } + + res.location = function location(){ + // TODO: Implement me! + } + + res.redirect = function redirect(){ + // TODO: Implement me! + } + + res.render = function render(){ + // TODO: Does this apply? + } + + res.send = function send(){ + // TODO: Does this apply? + } + + res.sendFile = function sendFile(){ + // TODO: Does this apply? + } + + res.sendStatus = function sendStatus(){ + // TODO: Implement me! + } + + res.set = function set(){ + // TODO: Implement me! + } + + res.status = function status(){ + // TODO: Implement me! + } + + res.type = function type(){ + // TODO: Implement me! + } + + res.vary = function vary(){ + // TODO: Implement me! + } + + return res; +} + diff --git a/_serverless/demo-app-posts/s-function.json b/_serverless/demo-app-posts/s-function.json new file mode 100644 index 0000000..ecf61c4 --- /dev/null +++ b/_serverless/demo-app-posts/s-function.json @@ -0,0 +1,51 @@ +{ + "name": "demo-app-posts", + "runtime": "nodejs4.3", + "description": "Serverless Lambda function for project: demo-app", + "customName": false, + "customRole": false, + "handler": "handler.handler", + "timeout": 6, + "memorySize": 1024, + "authorizer": {}, + "custom": { + "excludePatterns": [] + }, + "endpoints": [ + { + "path": "demo-app-posts", + "method": "GET", + "type": "AWS", + "authorizationType": "none", + "authorizerFunction": false, + "apiKeyRequired": false, + "requestParameters": {}, + "requestTemplates": "$${passthroughTemplate}", + "responses": { + "400": { + "statusCode": "400" + }, + "default": { + "statusCode": "200", + "responseParameters": {}, + "responseModels": { + "application/json;charset=UTF-8": "Empty" + }, + "responseTemplates": { + "application/json;charset=UTF-8": "" + } + } + } + } + ], + "events": [], + "environment": { + "SERVERLESS_PROJECT": "${project}", + "SERVERLESS_STAGE": "${stage}", + "SERVERLESS_REGION": "${region}" + }, + "vpc": { + "securityGroupIds": [], + "subnetIds": [] + } +} diff --git a/_serverless/demo-app-posts/s-templates.yaml b/_serverless/demo-app-posts/s-templates.yaml new file mode 100644 index 0000000..de5912b --- /dev/null +++ b/_serverless/demo-app-posts/s-templates.yaml @@ -0,0 +1,93 @@ +passthroughTemplate: + application/json: | + ## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html + ## This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload + #set($allParams = $input.params()) + { + "body-json" : "$input.json('$')", + "params" : { + #foreach($type in $allParams.keySet()) + #set($params = $allParams.get($type)) + "$type" : { + #foreach($paramName in $params.keySet()) + "$paramName" : "$util.escapeJavaScript($params.get($paramName))" + #if($foreach.hasNext),#end + #end + } + #if($foreach.hasNext),#end + #end + }, + "stage-variables" : { + #foreach($key in $stageVariables.keySet()) + "$key" : "$util.escapeJavaScript($stageVariables.get($key))" + #if($foreach.hasNext),#end + #end + }, + "context" : { + "account-id" : "$context.identity.accountId", + "api-id" : "$context.apiId", + "api-key" : "$context.identity.apiKey", + "authorizer-principal-id" : "$context.authorizer.principalId", + "caller" : "$context.identity.caller", + "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider", + "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType", + "cognito-identity-id" : "$context.identity.cognitoIdentityId", + "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId", + "http-method" : "$context.httpMethod", + "stage" : "$context.stage", + "source-ip" : "$context.identity.sourceIp", + "user" : "$context.identity.user", + "user-agent" : "$context.identity.userAgent", + "user-arn" : "$context.identity.userArn", + "request-id" : "$context.requestId", + "resource-id" : "$context.resourceId", + "resource-path" : "$context.resourcePath" + } + } +expressRequestTemplate: + application/json: | + { + "body": "$input.json('$')", + "headers": { + #foreach($header in $input.params().header.keySet()) + "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end + #end + }, + "method": "$context.httpMethod", + "params": { + #foreach($param in $input.params().path.keySet()) + "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end + #end + }, + "query": { + #foreach($queryParam in $input.params().querystring.keySet()) + "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end + #end + }, + "baseUrl": "$context.resourcePath", + "context": { + #foreach($contextItem in $context.keySet()) + "$contextItem": "$util.escapeJavaScript($context.get($contextItem))" #if($foreach.hasNext),#end + #end + } + } +fullRequestTemplate: + application/json: | + $input.json('$'), + "headers": { + #foreach($header in $input.params().header.keySet()) + "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end + #end + }, + "method": "$context.httpMethod", + "params": { + #foreach($param in $input.params().path.keySet()) + "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end + #end + }, + "query": { + #foreach($queryParam in $input.params().querystring.keySet()) + "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end + #end + } + } From f81b6628f3cbb9ef9e2c6857fd2a312401b85aba Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 15:26:16 -0500 Subject: [PATCH 09/18] Working on a generator for serverlss functions --- _serverless/_auto/demo-app-posts/handler.js | 12 +++ .../_auto/demo-app-posts/s-function.json | 51 ++++++++++ .../_auto/demo-app-posts/s-templates.yaml | 93 +++++++++++++++++++ demo-app-prepare-deploy.js | 20 ++++ serverless-generator.js | 54 +++++++++++ serverless-templates/s-function.json | 6 +- 6 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 _serverless/_auto/demo-app-posts/handler.js create mode 100644 _serverless/_auto/demo-app-posts/s-function.json create mode 100644 _serverless/_auto/demo-app-posts/s-templates.yaml create mode 100644 demo-app-prepare-deploy.js create mode 100644 serverless-generator.js diff --git a/_serverless/_auto/demo-app-posts/handler.js b/_serverless/_auto/demo-app-posts/handler.js new file mode 100644 index 0000000..bba5e78 --- /dev/null +++ b/_serverless/_auto/demo-app-posts/handler.js @@ -0,0 +1,12 @@ +const lambdaUtils = require('./lambda-utils'); + +const endpointLogic = require('./endpoint-logic'); + +module.exports.handler = function(event, context, cb) { + console.log('got event'); + console.log(JSON.stringify(event,null,'\t')); + var req = lambdaUtils.buildRequest(event,context,cb); + var res = lambdaUtils.buildResponse(event,context,cb); + endpointLogic.index(req, res); +}; + diff --git a/_serverless/_auto/demo-app-posts/s-function.json b/_serverless/_auto/demo-app-posts/s-function.json new file mode 100644 index 0000000..84f8a2b --- /dev/null +++ b/_serverless/_auto/demo-app-posts/s-function.json @@ -0,0 +1,51 @@ +{ + "name": "{{module}}", + "runtime": "nodejs4.3", + "description": "Serverless Lambda function for project: demo-app", + "customName": false, + "customRole": false, + "handler": "handler.handler", + "timeout": 6, + "memorySize": 1024, + "authorizer": {}, + "custom": { + "excludePatterns": [] + }, + "endpoints": [ + { + "path": "{{url}}", + "method": "{{method}}", + "type": "AWS", + "authorizationType": "none", + "authorizerFunction": false, + "apiKeyRequired": false, + "requestParameters": {}, + "requestTemplates": "$${passthroughTemplate}", + "responses": { + "400": { + "statusCode": "400" + }, + "default": { + "statusCode": "200", + "responseParameters": {}, + "responseModels": { + "application/json;charset=UTF-8": "Empty" + }, + "responseTemplates": { + "application/json;charset=UTF-8": "" + } + } + } + } + ], + "events": [], + "environment": { + "SERVERLESS_PROJECT": "${project}", + "SERVERLESS_STAGE": "${stage}", + "SERVERLESS_REGION": "${region}" + }, + "vpc": { + "securityGroupIds": [], + "subnetIds": [] + } +} diff --git a/_serverless/_auto/demo-app-posts/s-templates.yaml b/_serverless/_auto/demo-app-posts/s-templates.yaml new file mode 100644 index 0000000..de5912b --- /dev/null +++ b/_serverless/_auto/demo-app-posts/s-templates.yaml @@ -0,0 +1,93 @@ +passthroughTemplate: + application/json: | + ## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html + ## This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload + #set($allParams = $input.params()) + { + "body-json" : "$input.json('$')", + "params" : { + #foreach($type in $allParams.keySet()) + #set($params = $allParams.get($type)) + "$type" : { + #foreach($paramName in $params.keySet()) + "$paramName" : "$util.escapeJavaScript($params.get($paramName))" + #if($foreach.hasNext),#end + #end + } + #if($foreach.hasNext),#end + #end + }, + "stage-variables" : { + #foreach($key in $stageVariables.keySet()) + "$key" : "$util.escapeJavaScript($stageVariables.get($key))" + #if($foreach.hasNext),#end + #end + }, + "context" : { + "account-id" : "$context.identity.accountId", + "api-id" : "$context.apiId", + "api-key" : "$context.identity.apiKey", + "authorizer-principal-id" : "$context.authorizer.principalId", + "caller" : "$context.identity.caller", + "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider", + "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType", + "cognito-identity-id" : "$context.identity.cognitoIdentityId", + "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId", + "http-method" : "$context.httpMethod", + "stage" : "$context.stage", + "source-ip" : "$context.identity.sourceIp", + "user" : "$context.identity.user", + "user-agent" : "$context.identity.userAgent", + "user-arn" : "$context.identity.userArn", + "request-id" : "$context.requestId", + "resource-id" : "$context.resourceId", + "resource-path" : "$context.resourcePath" + } + } +expressRequestTemplate: + application/json: | + { + "body": "$input.json('$')", + "headers": { + #foreach($header in $input.params().header.keySet()) + "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end + #end + }, + "method": "$context.httpMethod", + "params": { + #foreach($param in $input.params().path.keySet()) + "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end + #end + }, + "query": { + #foreach($queryParam in $input.params().querystring.keySet()) + "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end + #end + }, + "baseUrl": "$context.resourcePath", + "context": { + #foreach($contextItem in $context.keySet()) + "$contextItem": "$util.escapeJavaScript($context.get($contextItem))" #if($foreach.hasNext),#end + #end + } + } +fullRequestTemplate: + application/json: | + $input.json('$'), + "headers": { + #foreach($header in $input.params().header.keySet()) + "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end + #end + }, + "method": "$context.httpMethod", + "params": { + #foreach($param in $input.params().path.keySet()) + "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end + #end + }, + "query": { + #foreach($queryParam in $input.params().querystring.keySet()) + "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end + #end + } + } diff --git a/demo-app-prepare-deploy.js b/demo-app-prepare-deploy.js new file mode 100644 index 0000000..fd0f123 --- /dev/null +++ b/demo-app-prepare-deploy.js @@ -0,0 +1,20 @@ +var Server = require('./server'); +var ServerlessGenerator = require('./serverless-generator'); + +var util = require('util'); + +var server = new Server(); + +server.routes(function() { + this.get('/posts', {from: 'demo-app-posts', with: 'index'}); +}); + +var routes = server.toJSON(); + +routes.routes.forEach(function(route){ + console.log('about to generate serverless function + endpiont'); + console.log(route); + ServerlessGenerator.generateRoute(route); +}); + +console.log(routes) diff --git a/serverless-generator.js b/serverless-generator.js new file mode 100644 index 0000000..73c55fe --- /dev/null +++ b/serverless-generator.js @@ -0,0 +1,54 @@ + +const fs = require('fs'); + +function preflight(route){ + makeAutoDir(); + makeRouteDir(route); +} + +function buildRoutePath(route){ + return `_serverless/_auto/${route.module}`; +} + +function templateDestinationPath(route, template){ + return `${buildRoutePath(route)}/${template}` +} + +function makeAutoDir(){ + try{ + fs.accessSync('_serverless/_auto'); + }catch(error){ + fs.mkdirSync(`_serverless/_auto`); + } +} + +function makeRouteDir(route){ + const routePath = buildRoutePath(route); + try{ + fs.accessSync(routePath); + }catch(error){ + fs.mkdirSync(routePath); + } +} + +function copyTemplate(route, template){ + var destination = templateDestinationPath(route,template); + var source = `serverless-templates/${template}`; + fs.createReadStream(source).pipe(fs.createWriteStream(destination)); +} + +function copyTemplates(route){ + copyTemplate(route,'handler.js'); + copyTemplate(route,'s-function.json'); + copyTemplate(route,'s-templates.yaml'); +} + + +module.exports.generateRoute = function(route){ + console.log('in generateRoute -----------'); + console.log(route); + console.log('-------------------'); + + preflight(route); + copyTemplates(route); +} diff --git a/serverless-templates/s-function.json b/serverless-templates/s-function.json index ecf61c4..84f8a2b 100644 --- a/serverless-templates/s-function.json +++ b/serverless-templates/s-function.json @@ -1,5 +1,5 @@ { - "name": "demo-app-posts", + "name": "{{module}}", "runtime": "nodejs4.3", "description": "Serverless Lambda function for project: demo-app", "customName": false, @@ -13,8 +13,8 @@ }, "endpoints": [ { - "path": "demo-app-posts", - "method": "GET", + "path": "{{url}}", + "method": "{{method}}", "type": "AWS", "authorizationType": "none", "authorizerFunction": false, From 817b58bf9db52a5386f2c3f50fda45c549b2c768 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 15:47:32 -0500 Subject: [PATCH 10/18] Commit autogenerated changes --- .../_auto/demo-app-posts/endpoint-logic.js | 6 + .../_auto/demo-app-posts/lambda-utils.js | 0 .../_auto/demo-app-posts/s-function.json | 6 +- serverless-templates/lambda-utils.js | 156 ++++++++++++++++++ 4 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 _serverless/_auto/demo-app-posts/endpoint-logic.js rename lambda-utils.js => _serverless/_auto/demo-app-posts/lambda-utils.js (100%) create mode 100644 serverless-templates/lambda-utils.js diff --git a/_serverless/_auto/demo-app-posts/endpoint-logic.js b/_serverless/_auto/demo-app-posts/endpoint-logic.js new file mode 100644 index 0000000..36feef7 --- /dev/null +++ b/_serverless/_auto/demo-app-posts/endpoint-logic.js @@ -0,0 +1,6 @@ +module.exports = { + index: function(req, res) { + res.status(200); + res.json({ message: "ohai!!!"}); + } +}; diff --git a/lambda-utils.js b/_serverless/_auto/demo-app-posts/lambda-utils.js similarity index 100% rename from lambda-utils.js rename to _serverless/_auto/demo-app-posts/lambda-utils.js diff --git a/_serverless/_auto/demo-app-posts/s-function.json b/_serverless/_auto/demo-app-posts/s-function.json index 84f8a2b..4a9a443 100644 --- a/_serverless/_auto/demo-app-posts/s-function.json +++ b/_serverless/_auto/demo-app-posts/s-function.json @@ -1,5 +1,5 @@ { - "name": "{{module}}", + "name": "demo-app-posts", "runtime": "nodejs4.3", "description": "Serverless Lambda function for project: demo-app", "customName": false, @@ -13,8 +13,8 @@ }, "endpoints": [ { - "path": "{{url}}", - "method": "{{method}}", + "path": "/posts", + "method": "GET", "type": "AWS", "authorizationType": "none", "authorizerFunction": false, diff --git a/serverless-templates/lambda-utils.js b/serverless-templates/lambda-utils.js new file mode 100644 index 0000000..e9ce029 --- /dev/null +++ b/serverless-templates/lambda-utils.js @@ -0,0 +1,156 @@ +module.exports.buildRequest = function(event, context, cb) { + var req = {}; + + // http://expressjs.com/en/api.html#req + // Properties + req.app = null; // Not sure this applies in our context... + req.baseUrl = event.baseUrl; + req.body = event.body; + req.cookies = {}; // TODO : Figure out how to get cookies from AWS Gateway + req.fresh = true; // TODO : Does this apply in our context? + req.hostname = event.params.header.Host; + //req.ip = event.params.header["X-Forwarded-For"].split(", ")[0]; + req.ips = event.params.header["X-Forwarded-For"]; + req.method = event.method; + req.originalUrl = ""; // TODO : Figrure out how to reconstruct this + req.params = event.params; + req.path = event.baseUrl; // TODO : This isn't quite right... + req.protocol = event.params.header["X-Forwarded-Proto"]; + req.query = event.query; + req.route = null; // TODO : Does this apply to us? + req.secure = req.protocol === 'https'; + req.signedCookies = {}; // TODO : ??? + req.stale = false; // TODO : Does this apply in our context? + req.subdomains = []; // TODO: Does this apply? + req.xhr = event.params.header["X-Requested-With"] === 'XMLHttpRequest'; + + // Methods + /* + var accept = realAccepts(req); + req.accepts = function accepts(types){ + // TODO : Fix me! + return types; + //return accept.type(types); + }; + */ + req.acceptsCharsets = function acceptsCharsets(){ + // TODO : Fix me! + }; + + req.acceptsEncodings = function acceptsEncodings(){ + // TODO : Fix me! + }; + + req.acceptsLanguages = function acceptsLanguages(){ + // TODO : Fix me! + }; + + req.get = function get(field){ + return event.params.header[field]; + } + + req.is = function is(type){ + // TODO: Fix me! + } + + return req; +} + +module.exports.buildResponse = function(event, context, cb) { + var res = {}; + + // Properties + res.app = null; // TODO : Does this apply? + res.headersSent = false; // TODO : Is this right? + res.locals = {}; // TODO: Does this apply? + + res.headers = []; + + // Methods + res.append = function append(field,value){ + res.headers.push([field,value]); + } + + res.attachment = function attachment(){ + // TODO: Can we return attachments through API Gatewway? + } + + res.cookie = function cookie(name, value, options){ + // TODO: Can we set cookies? + } + + res.clearCookie = function clearCookie(name, options){ + // TODO: Can we set cookies? + } + + res.download = function download(){ + // TODO: Can we do this? + } + + res.end = function end(){ + // TODO: Implement me! + } + + res.format = function format(){ + // TODO: does this apply? + } + + res.get = function get(field){ + return headers[field]; + } + + res.json = function json(payload){ + cb(null, payload); + } + + res.jsonp = function jsonp(){ + // TODO: Do we need to support josnp? + } + + res.links = function links(){ + // TODO: Implement me! + } + + res.location = function location(){ + // TODO: Implement me! + } + + res.redirect = function redirect(){ + // TODO: Implement me! + } + + res.render = function render(){ + // TODO: Does this apply? + } + + res.send = function send(){ + // TODO: Does this apply? + } + + res.sendFile = function sendFile(){ + // TODO: Does this apply? + } + + res.sendStatus = function sendStatus(){ + // TODO: Implement me! + } + + res.set = function set(){ + // TODO: Implement me! + } + + res.status = function status(){ + // TODO: Implement me! + } + + res.type = function type(){ + // TODO: Implement me! + } + + res.vary = function vary(){ + // TODO: Implement me! + } + + return res; +} + From 4aed3b46b38da3b61ff607812c12ab4cc2224a99 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 15:47:57 -0500 Subject: [PATCH 11/18] Change the name of the manually generated one to mvoe it out of the way --- _serverless/demo-app-posts/s-function.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_serverless/demo-app-posts/s-function.json b/_serverless/demo-app-posts/s-function.json index ecf61c4..e9e3461 100644 --- a/_serverless/demo-app-posts/s-function.json +++ b/_serverless/demo-app-posts/s-function.json @@ -1,5 +1,5 @@ { - "name": "demo-app-posts", + "name": "manual-demo-app-posts", "runtime": "nodejs4.3", "description": "Serverless Lambda function for project: demo-app", "customName": false, From 8025793b15c8ea137849974d6bcef5bd9ffa7241 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 15:48:28 -0500 Subject: [PATCH 12/18] Beef up the serverless generator --- serverless-generator.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/serverless-generator.js b/serverless-generator.js index 73c55fe..cecee51 100644 --- a/serverless-generator.js +++ b/serverless-generator.js @@ -32,6 +32,7 @@ function makeRouteDir(route){ } function copyTemplate(route, template){ + console.log(`copying template ${template}`) var destination = templateDestinationPath(route,template); var source = `serverless-templates/${template}`; fs.createReadStream(source).pipe(fs.createWriteStream(destination)); @@ -39,10 +40,25 @@ function copyTemplate(route, template){ function copyTemplates(route){ copyTemplate(route,'handler.js'); - copyTemplate(route,'s-function.json'); copyTemplate(route,'s-templates.yaml'); + copyTemplate(route,'lambda-utils.js'); } +function updateSFunction(route){ + var readPath = `serverless-templates/s-function.json` + var writePath = templateDestinationPath(route, 's-function.json'); + var contents = fs.readFileSync(readPath, {encoding:"utf8"}); + contents = contents.replace(/{{module}}/g,route.module); + contents = contents.replace(/{{method}}/g,route.method); + contents = contents.replace(/{{url}}/g,route.url); + fs.writeFileSync(writePath,contents); +} + +function copyModule(route){ + var destination = templateDestinationPath(route,'endpoint-logic.js'); + var source = `${route.module}.js`; + fs.createReadStream(source).pipe(fs.createWriteStream(destination)); +} module.exports.generateRoute = function(route){ console.log('in generateRoute -----------'); @@ -51,4 +67,6 @@ module.exports.generateRoute = function(route){ preflight(route); copyTemplates(route); + updateSFunction(route); + copyModule(route); } From 79f55c0facdee17a0e6c172075ee0a6a55d67337 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 11:06:19 -0500 Subject: [PATCH 13/18] Extract the app router --- demo-app.js | 7 ++++--- demo-router.js | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 demo-router.js diff --git a/demo-app.js b/demo-app.js index 59f5040..b2b8f07 100644 --- a/demo-app.js +++ b/demo-app.js @@ -1,11 +1,12 @@ var Server = require('./server'); +var Router = require('./demo-router'); + var util = require('util'); var server = new Server(); +var router = new Router(); -server.routes(function() { - this.get('/posts', {from: 'demo-app-posts', with: 'index'}); -}); +router.loadRoutes(server); server.start(3000); diff --git a/demo-router.js b/demo-router.js new file mode 100644 index 0000000..cbca409 --- /dev/null +++ b/demo-router.js @@ -0,0 +1,13 @@ +function Router() { + +} + +Router.prototype.loadRoutes = function(server){ + + server.routes(function() { + this.get('/posts', {from: 'demo-app-posts', with: 'index'}); + }); + +} + +module.exports = Router; From 36520da60bae1498a4c0a2203f9e9422945b04d1 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 15:55:45 -0500 Subject: [PATCH 14/18] use the extracted router --- demo-app-prepare-deploy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo-app-prepare-deploy.js b/demo-app-prepare-deploy.js index fd0f123..4b123f3 100644 --- a/demo-app-prepare-deploy.js +++ b/demo-app-prepare-deploy.js @@ -1,13 +1,13 @@ var Server = require('./server'); +var Router = require('./demo-router'); var ServerlessGenerator = require('./serverless-generator'); var util = require('util'); var server = new Server(); +var router = new Router(); -server.routes(function() { - this.get('/posts', {from: 'demo-app-posts', with: 'index'}); -}); +router.loadRoutes(server); var routes = server.toJSON(); From c4335a421f9a3df672837752a23507a5eea752a1 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Sat, 4 Jun 2016 15:55:54 -0500 Subject: [PATCH 15/18] Commit auto generated stuff --- _serverless/_auto/demo-app-posts/endpoint-logic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_serverless/_auto/demo-app-posts/endpoint-logic.js b/_serverless/_auto/demo-app-posts/endpoint-logic.js index 36feef7..8b68f29 100644 --- a/_serverless/_auto/demo-app-posts/endpoint-logic.js +++ b/_serverless/_auto/demo-app-posts/endpoint-logic.js @@ -1,6 +1,6 @@ module.exports = { index: function(req, res) { res.status(200); - res.json({ message: "ohai!!!"}); + res.json({ message: "ohai"}); } }; From 17b5fec5fafbf15d9eeed45c51d1a488eb014f2a Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Thu, 16 Jun 2016 09:24:43 -0500 Subject: [PATCH 16/18] Clean up s-templates.yaml --- .../_auto/demo-app-posts/s-templates.yaml | 47 ------------------- serverless-templates/s-templates.yaml | 47 ------------------- 2 files changed, 94 deletions(-) diff --git a/_serverless/_auto/demo-app-posts/s-templates.yaml b/_serverless/_auto/demo-app-posts/s-templates.yaml index de5912b..a2729c5 100644 --- a/_serverless/_auto/demo-app-posts/s-templates.yaml +++ b/_serverless/_auto/demo-app-posts/s-templates.yaml @@ -44,50 +44,3 @@ passthroughTemplate: "resource-path" : "$context.resourcePath" } } -expressRequestTemplate: - application/json: | - { - "body": "$input.json('$')", - "headers": { - #foreach($header in $input.params().header.keySet()) - "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end - #end - }, - "method": "$context.httpMethod", - "params": { - #foreach($param in $input.params().path.keySet()) - "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end - #end - }, - "query": { - #foreach($queryParam in $input.params().querystring.keySet()) - "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end - #end - }, - "baseUrl": "$context.resourcePath", - "context": { - #foreach($contextItem in $context.keySet()) - "$contextItem": "$util.escapeJavaScript($context.get($contextItem))" #if($foreach.hasNext),#end - #end - } - } -fullRequestTemplate: - application/json: | - $input.json('$'), - "headers": { - #foreach($header in $input.params().header.keySet()) - "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end - #end - }, - "method": "$context.httpMethod", - "params": { - #foreach($param in $input.params().path.keySet()) - "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end - #end - }, - "query": { - #foreach($queryParam in $input.params().querystring.keySet()) - "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end - #end - } - } diff --git a/serverless-templates/s-templates.yaml b/serverless-templates/s-templates.yaml index de5912b..a2729c5 100644 --- a/serverless-templates/s-templates.yaml +++ b/serverless-templates/s-templates.yaml @@ -44,50 +44,3 @@ passthroughTemplate: "resource-path" : "$context.resourcePath" } } -expressRequestTemplate: - application/json: | - { - "body": "$input.json('$')", - "headers": { - #foreach($header in $input.params().header.keySet()) - "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end - #end - }, - "method": "$context.httpMethod", - "params": { - #foreach($param in $input.params().path.keySet()) - "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end - #end - }, - "query": { - #foreach($queryParam in $input.params().querystring.keySet()) - "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end - #end - }, - "baseUrl": "$context.resourcePath", - "context": { - #foreach($contextItem in $context.keySet()) - "$contextItem": "$util.escapeJavaScript($context.get($contextItem))" #if($foreach.hasNext),#end - #end - } - } -fullRequestTemplate: - application/json: | - $input.json('$'), - "headers": { - #foreach($header in $input.params().header.keySet()) - "$header": "$util.escapeJavaScript($input.params().header.get($header))" #if($foreach.hasNext),#end - #end - }, - "method": "$context.httpMethod", - "params": { - #foreach($param in $input.params().path.keySet()) - "$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end - #end - }, - "query": { - #foreach($queryParam in $input.params().querystring.keySet()) - "$queryParam": "$util.escapeJavaScript($input.params().querystring.get($queryParam))" #if($foreach.hasNext),#end - #end - } - } From b846675f4fb4ccc639cfd60cb803f9d1447c26c6 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Thu, 16 Jun 2016 09:27:24 -0500 Subject: [PATCH 17/18] Add README --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..2450286 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# untitled-serverless + +## Deploying to AWS Lambda & API Gateway + +```bash +node demo-app-prepare-deploy.js +cd _serverless +sls dash deploy +``` + + From 06a520149dc67f9453a87e5b65a3f422f85bb028 Mon Sep 17 00:00:00 2001 From: Jeremy Green Date: Fri, 17 Jun 2016 07:49:53 -0500 Subject: [PATCH 18/18] Readme tweak --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 2450286..e25fb6b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ ## Deploying to AWS Lambda & API Gateway +The _serverless directory contains a serverless project (generated with sls project create _serverless), and the _serverless/_auto directory is the target for the automatically built artifacts. + +To deploy: + ```bash node demo-app-prepare-deploy.js cd _serverless