Skip to content

Instantly share code, notes, and snippets.

@justinsoliz
Last active August 10, 2017 15:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save justinsoliz/95aadf1ce9ce4114915ed2552dcd260d to your computer and use it in GitHub Desktop.
Save justinsoliz/95aadf1ce9ce4114915ed2552dcd260d to your computer and use it in GitHub Desktop.
express + aws serverless proxy
{
"presets": [ "es2015", "flow" ],
"plugins": ["transform-object-rest-spread"]
}
{
"parser": "babel-eslint",
"extends": [
"eslint:recommended",
"plugin:flowtype/recommended"
],
"env": {
"browser": false,
"node": true,
"mocha": true,
"es6": true,
"jest": true
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
},
"rules": {
"quotes": [2, "single", { "avoidEscape": true, "allowTemplateLiterals": true }]
},
"plugins": [ "flowtype" ]
}
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.setHeader('X-API-Version', '1.0.0');
res.status(200).json({ success: true });
});
app.get('/health-check', (req, res) => {
res.setHeader('X-API-Version', '1.0.0');
res.status(200).json({ healthCheck: true });
});
export default app;
import request from 'supertest';
import app from '../index';
import { version } from './package.json';
describe('Health check', () => {
it('should complete health check with correct version', () => {
return request(app).get('/health-check')
.expect(200)
.then(res => {
expect(res.headers['x-api-version']).toEqual(version);
});
});
it('should complete health check', () => {
return request(app).get('/health-check')
.expect(200);
});
});
import awsServerlessExpress from 'aws-serverless-express';
import app from './';
const server = awsServerlessExpress.createServer(app);
exports.handler = (event, context) =>
awsServerlessExpress.proxy(server, event, context);
provider "aws" {
region = "${var.aws_region}"
}
# API Gateway
resource "aws_api_gateway_rest_api" "demo_api" {
name = "demo_api"
}
resource "aws_api_gateway_deployment" "demo_api_deployment" {
depends_on = [
"aws_api_gateway_method.demo_method",
"aws_api_gateway_integration_response.api_demo_integration_response"
]
rest_api_id = "${aws_api_gateway_rest_api.demo_api.id}"
stage_name = "demo"
variables = {
"version" = "1.0.0"
}
}
resource "aws_api_gateway_method" "demo_method" {
rest_api_id = "${aws_api_gateway_rest_api.demo_api.id}"
resource_id = "${aws_api_gateway_resource.demo_proxy_resource.id}"
http_method = "ANY"
authorization = "NONE"
}
resource "aws_api_gateway_resource" "demo_proxy_resource" {
rest_api_id = "${aws_api_gateway_rest_api.demo_api.id}"
parent_id = "${aws_api_gateway_rest_api.demo_api.root_resource_id}"
path_part = "{proxy+}"
}
resource "aws_api_gateway_integration" "demo_integration" {
depends_on = [
"aws_api_gateway_resource.demo_proxy_resource"
]
rest_api_id = "${aws_api_gateway_rest_api.demo_api.id}"
resource_id = "${aws_api_gateway_resource.demo_proxy_resource.id}"
http_method = "${aws_api_gateway_method.demo_method.http_method}"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "arn:aws:apigateway:${var.aws_region}:lambda:path/2015-03-31/functions/${aws_lambda_function.demo_api_gateway_lambda.arn}/invocations"
}
resource "aws_api_gateway_method_response" "200" {
rest_api_id = "${aws_api_gateway_rest_api.demo_api.id}"
resource_id = "${aws_api_gateway_resource.demo_proxy_resource.id}"
http_method = "${aws_api_gateway_method.demo_method.http_method}"
status_code = "200"
response_models = {
"application/json" = "Empty"
}
}
resource "aws_api_gateway_integration_response" "api_demo_integration_response" {
depends_on = [
"aws_api_gateway_method.demo_method",
"aws_api_gateway_method_response.200"
]
rest_api_id = "${aws_api_gateway_rest_api.demo_api.id}"
resource_id = "${aws_api_gateway_resource.demo_proxy_resource.id}"
http_method = "${aws_api_gateway_method.demo_method.http_method}"
status_code = "${aws_api_gateway_method_response.200.status_code}"
response_templates = {
"application/json" = ""
}
}
# Lambda
resource "aws_lambda_permission" "apigw_lambda" {
statement_id = "AllowExecutionFromAPIGateway"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.demo_api_gateway_lambda.arn}"
principal = "apigateway.amazonaws.com"
source_arn = "arn:aws:execute-api:${var.aws_region}:${var.aws_account}:${aws_api_gateway_rest_api.demo_api.id}/*/*/*"
}
resource "aws_lambda_function" "demo_api_gateway_lambda" {
s3_bucket = "terraform-packages"
s3_key = "api.zip"
function_name = "api_gateway_demo_lambda_function"
role = "${aws_iam_role.demo_api_gateway_lambda_role.arn}"
handler = "lib/lambda_handler.handler"
runtime = "nodejs4.3"
timeout = "15"
environment = {
variables = {
NODE_ENV = "production"
}
}
}
# IAM
resource "aws_iam_role" "demo_api_gateway_lambda_role" {
name = "demo-api-gateway-lambda-role"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "lambda_iam_policy_basic_execution" {
role = "${aws_iam_role.demo_api_gateway_lambda_role.id}"
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
{
"name": "demo_api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"private": true,
"scripts": {
"start": "babel-node ./lib/server.js",
"test": "jest -i --coverage ./test/**/*.spec.js",
"compile": "babel lib -d ./.build/lib",
"lint": "eslint lib/**/*.js test/**/*.js --cache"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-cli": "^6.5.1",
"babel-core": "^6.5.2",
"babel-jest": "^19.0.0",
"babel-preset-es2015": "^6.5.0",
"eslint": "^3.0.0",
"jest": "^19.0.2",
"supertest": "^3.0.0"
},
"dependencies": {
"aws-serverless-express": "^2.2.0",
"cors": "^2.7.1",
"express": "^4.13.4"
},
"jest": {
"automock": false,
"testEnvironment": "node"
}
}
import axios from 'axios';
import { version } from './package.json';
import { apiHost } from './config';
describe('Health Check Regression Tests', () => {
let client;
beforeEach(() => {
client = axios.create({ baseURL: `http://${apiHost}` });
});
it('should return correct api version', () => {
return client.get('/health-check').then(res => {
expect(res.status).toEqual(200);
expect(res.headers['x-api-version']).toEqual(version);
});
});
});
import app from './index';
const port = 8000;
app.listen(port, (err) => {
if (err) {
console.log('error', err);
} else {
console.log('info', '==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.', port, port)
}
});
export default app;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment