Skip to content

Commit

Permalink
FIXME #3 #4 #5
Browse files Browse the repository at this point in the history
  • Loading branch information
nnthanh101 committed Feb 25, 2021
1 parent b597928 commit 6537fb3
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 7 deletions.
46 changes: 46 additions & 0 deletions projects/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<title>Simple Web Service</title>
<style>

pre {
background: #eee;
border-radius: 4px;
padding: 1em;
}

form {
margin: 1em;
}

</style>
</head>
<body>
<h1>Simple Web Service</h1>
Enter something in the box below and hit the button:

<form id="form">
<input type="text" id="input">
<input type="submit" id="btn" value="Submit">
</form>
<pre id="output">
</pre>
<script src="//code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$('#form').submit(e => {
if (e.preventDefault) { e.preventDefault(); }

// Send input to server
$.post('/api/', { input: $('#input').val() }).then(output => {
$('#output').text(JSON.stringify(output, undefined, 2));
});

// Clear text box
$('#input').val('');

return false;
});
</script>
</body>
</html>
6 changes: 3 additions & 3 deletions serverless-webapp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ This [CDK Pattern](https://cdkpatterns.com/patterns/) to make deploying a Dynami
/modernapps/serverless-webapp
├── README.md
├── bin
| └── sserverless-webapp.ts
| └── serverless-webapp.ts
├── cdk.json
├── jest.config.js
├── lib
| └── sserverless-webapp-stack.ts
| └── serverless-webapp-stack.ts
├── package.json
├── test
| └── sserverless-webapp.test.ts
| └── serverless-webapp.test.ts
└── tsconfig.json
```

Expand Down
10 changes: 9 additions & 1 deletion serverless-webapp/bin/serverless-webapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { ServerlessWebappStack } from '../lib/serverless-webapp-stack';
import { applicationMetaData } from '../config/config';

const app = new cdk.App();
new ServerlessWebappStack(app, 'ServerlessWebappStack');

new ServerlessWebappStack(app, 'ServerlessWebappStack', {
domainName: applicationMetaData.domainName,
// FIXME #3
// certificate: applicationMetaData.certificate,
// table: db.table,
// monitoring
});
8 changes: 8 additions & 0 deletions serverless-webapp/config/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** Configuration file */
export const applicationMetaData = {
account: "${AWS_ACCOUNT}",
region: "${AWS_REGION}",

/** Primary Route53 Domain */
domainName: "web.job4u.vn",
}
30 changes: 30 additions & 0 deletions serverless-webapp/lib/monitoring-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import * as cdk from '@aws-cdk/core';
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';

/**
* Interface that downstream stacks expect to monitoring subsystem.
*/
export interface IMonitoring {
addGraphs(title: string, ...widgets: cloudwatch.IWidget[]): void;
}

/**
* Class with monitoring facilities.
*/
export class MonitoringStack extends cdk.Stack implements IMonitoring {
private dashboard: cloudwatch.Dashboard;

constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

this.dashboard = new cloudwatch.Dashboard(this, 'Serverless-Webapp Dashboard');
}

public addGraphs(title: string, ...widgets: cloudwatch.IWidget[]): void {
this.dashboard.addWidgets(new cloudwatch.TextWidget({
markdown: `# ${title}`,
}));
this.dashboard.addWidgets(...widgets);
}

}
132 changes: 130 additions & 2 deletions serverless-webapp/lib/serverless-webapp-stack.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,137 @@
import * as cdk from '@aws-cdk/core';

import * as apigateway from '@aws-cdk/aws-apigateway';
import * as certmgr from '@aws-cdk/aws-certificatemanager';
import * as dynamodb from '@aws-cdk/aws-dynamodb';
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';
import * as cloudfront from '@aws-cdk/aws-cloudfront';
import * as s3 from '@aws-cdk/aws-s3';
import * as s3deploy from '@aws-cdk/aws-s3-deployment';
import * as origins from '@aws-cdk/aws-cloudfront-origins';
import * as lambda from '@aws-cdk/aws-lambda';
import { IMonitoring } from './monitoring-stack';

/** ServerlessWebapp StackProps */
export interface WebAppStackProps extends cdk.StackProps {

/**
* Domain name for the CloudFront distribution
* (Requires 'certificate' to be set)
* @default - Automatically generated domain name under CloudFront domain
*/
readonly domainName?: string;

/**
* Certificate for the CloudFront distribution
* (Requires 'domainName' to be set)
* @default - Automatically generated domain name under CloudFront domain
*/
readonly certificate?: certmgr.ICertificate;

/**
* Table to use as backing store for the Lambda Function
*/
// readonly table: dynamodb.ITable;

/**
* Where to add metrics
*/
// readonly monitoring: IMonitoring;
}

/**
* Serverless Web-App Stack.
*/
export class ServerlessWebappStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
constructor(scope: cdk.Construct, id: string, props: WebAppStackProps) {
super(scope, id, props);

// The code that defines your stack goes here

/** Step 1. Route53-Domain & ACM-Certificate */
if (!!props.domainName !== !!props.certificate) {
throw new Error('Supply either both or neither of \'domainName\' and \'certificate\'');
}

/**
* FIXME #4
*
* Step 2. Lambda & API-Gateway
*/
// const func = new lambda.Function(this, 'Lambda', {
// runtime: lambda.Runtime.NODEJS_14_X,
// handler: 'index.handler',
// code: lambda.Code.fromAsset(`${__dirname}/../build/src/lambda-handlers/lambda-handlers`),
// environment: {
// TABLE_ARN: props.table.tableArn
// },
// timeout: cdk.Duration.seconds(10),
// });

// props.table.grantReadWriteData(func);

// const apiGateway = new apigateway.LambdaRestApi(this, 'API-Gateway', {
// handler: func,
// endpointTypes: [apigateway.EndpointType.REGIONAL],
// });

/**
* Step 3. S3 bucket & Cloudfront distribution
*/

/** 3.1. S3 bucket to hold the Website with a CloudFront distribution */
// const bucket = new s3.Bucket(this, 'Bucket', {
// removalPolicy: cdk.RemovalPolicy.DESTROY,
// });
// const distribution = new cloudfront.Distribution(this, 'Dist', {
// defaultBehavior: { origin: new origins.S3Origin(bucket) },
// additionalBehaviors: {
// '/api/*': {
// origin: new origins.HttpOrigin(`${apiGateway.restApiId}.execute-api.${this.region}.amazonaws.com`, {
// originPath: `/${apiGateway.deploymentStage.stageName}`,
// }),
// allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
// cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
// },
// },
// defaultRootObject: 'index.html',
// domainNames: props.domainName ? [props.domainName] : undefined,
// certificate: props.certificate,
// });

/** 3.2. Upload assets to the S3 bucket */
// new s3deploy.BucketDeployment(this, 'Deploy', {
// destinationBucket: bucket,
// sources: [s3deploy.Source.asset(`${__dirname}/../../projects/web`)],
// distribution,
// prune: false,
// });

/**
* FIXME #5
* Monitoring: 99% of the requests should be faster than given latency.
* E301: latency 3 seconds
*/
// props.monitoring.addGraphs('Application',
// new cloudwatch.GraphWidget({
// title: 'P99 Latencies',
// left: [
// apiGateway.metricLatency({ statistic: 'P99' }),
// apiGateway.metricIntegrationLatency({ statistic: 'P99' }),
// ],
// }),

// new cloudwatch.GraphWidget({
// title: 'Counts vs errors',
// left: [
// apiGateway.metricCount(),
// ],
// right: [
// apiGateway.metricClientError(),
// apiGateway.metricServerError(),
// ],
// }),
// );

}
}
}
13 changes: 13 additions & 0 deletions serverless-webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions serverless-webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"typescript": "~3.9.7"
},
"dependencies": {
"@aws-cdk/aws-cloudfront-origins": "^1.91.0",
"@aws-cdk/aws-codepipeline": "^1.91.0",
"@aws-cdk/aws-dynamodb": "^1.91.0",
"@aws-cdk/aws-lambda": "^1.91.0",
Expand Down
14 changes: 14 additions & 0 deletions serverless-webapp/src/lambda-handlers/healthcheck/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* FIXME #4
* 1. Health Check
* 2. Version
*/
export async function handler(event: any, _context: any) {
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(event, undefined, 2),
};
}
9 changes: 8 additions & 1 deletion serverless-webapp/test/serverless-webapp.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { expect as expectCDK, matchTemplate, MatchStyle } from '@aws-cdk/assert';
import * as cdk from '@aws-cdk/core';
import { applicationMetaData } from '../config/config';
import * as ServerlessWebapp from '../lib/serverless-webapp-stack';

test('Empty Stack', () => {
const app = new cdk.App();
// WHEN
const stack = new ServerlessWebapp.ServerlessWebappStack(app, 'MyTestStack');
const stack = new ServerlessWebapp.ServerlessWebappStack(app, 'MyTestStack', {
domainName: applicationMetaData.domainName,
// FIXME #3
// certificate: applicationMetaData.certificate,
// table: db.table,
// monitoring
});
// THEN
expectCDK(stack).to(matchTemplate({
"Resources": {}
Expand Down

0 comments on commit 6537fb3

Please sign in to comment.