diff --git a/typescript/my-widget-service/resources/widgets.js b/typescript/my-widget-service/resources/widgets.js new file mode 100644 index 000000000..74d47efa8 --- /dev/null +++ b/typescript/my-widget-service/resources/widgets.js @@ -0,0 +1,138 @@ +//snippet-comment:[These are tags for the AWS doc team's sample catalog. Do not remove.] +//snippet-comment:[This should be in the resources/ directory] +//snippet-comment:[and only works with my_widget_service.ts in the bin/ directory] +//snippet-comment:[and widget_service.ts in the lib/ directory.] +//snippet-sourceauthor:[Doug-AWS] +//snippet-sourcedescription:[Lambda function to handle GET, POST, and DELETE.] +//snippet-keyword:[CDK V0.24.1] +//snippet-keyword:[S3.deleteObject function] +//snippet-keyword:[S3.getObject function] +//snippet-keyword:[S3.listObjectsV2 function] +//snippet-keyword:[S3.putObject function] +//snippet-keyword:[JavaScript] +//snippet-service:[cdk] +//snippet-sourcetype:[full-example] +//snippet-sourcedate:[2019-2-8] +// Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// This file is licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, either express or implied. See the License for the specific +// language governing permissions and limitations under the License. +//snippet-start:[cdk.typescript.widgets] +//snippet-start:[cdk.typescript.widgets.imports] +const AWS = require('aws-sdk'); +const S3 = new AWS.S3(); +//snippet-end:[cdk.typescript.widgets.imports] + +const bucketName = process.env.BUCKET; + +//snippet-start:[cdk.typescript.widgets.exports_main] +exports.main = async function(event, context) { + try { + var method = event.httpMethod; + // Get name, if present + var widgetName = event.path.startsWith('/') ? event.path.substring(1) : event.path; + + if (method === "GET") { + // GET / to get the names of all widgets + if (event.path === "/") { + const data = await S3.listObjectsV2({ Bucket: bucketName }).promise(); + var body = { + widgets: data.Contents.map(function(e) { return e.Key }) + }; + return { + statusCode: 200, + headers: {}, + body: JSON.stringify(body) + }; + } + + if (widgetName) { + // GET /name to get info on widget name + const data = await S3.getObject({ Bucket: bucketName, Key: widgetName}).promise(); + var body = data.Body.toString('utf-8'); + + return { + statusCode: 200, + headers: {}, + body: JSON.stringify(body) + }; + } + } + + if (method === "POST") { + // POST /name + // Return error if we do not have a name + if (!widgetName) { + return { + statusCode: 400, + headers: {}, + body: "Widget name missing" + }; + } + + // Create some dummy data to populate object + const now = new Date(); + var data = widgetName + " created: " + now; + + var base64data = new Buffer(data, 'binary'); + + await S3.putObject({ + Bucket: bucketName, + Key: widgetName, + Body: base64data, + ContentType: 'application/json' + }).promise(); + + return { + statusCode: 200, + headers: {}, + body: JSON.stringify(event.widgets) + }; + } + + if (method === "DELETE") { + // DELETE /name + // Return an error if we do not have a name + if (!widgetName) { + return { + statusCode: 400, + headers: {}, + body: "Widget name missing" + }; + } + + await S3.deleteObject({ + Bucket: bucketName, Key: widgetName + }).promise(); + + return { + statusCode: 200, + headers: {}, + body: "Successfully deleted widget " + widgetName + }; + } + + // We got something besides a GET, POST, or DELETE + return { + statusCode: 400, + headers: {}, + body: "We only accept GET, POST, and DELETE, not " + method + }; + } catch(error) { + var body = error.stack || JSON.stringify(error, null, 2); + return { + statusCode: 400, + headers: {}, + body: body + } + } +} +//snippet-end:[cdk.typescript.widgets.exports_main] +//snippet-end:[cdk.typescript.widgets] diff --git a/typescript/my-widget-service/widget_service.ts b/typescript/my-widget-service/widget_service.ts new file mode 100644 index 000000000..2376d8e96 --- /dev/null +++ b/typescript/my-widget-service/widget_service.ts @@ -0,0 +1,81 @@ +// snippet-comment:[These are tags for the AWS doc team's sample catalog. Do not remove.] +// snippet-comment:[This should be in the lib/ directory] +// snippet-comment:[and only works with my_widget_service.ts in the bin/ directory] +// snippet-comment:[and widgets.js in the resources/ directory.] +// snippet-sourceauthor:[Doug-AWS] +// snippet-sourcedescription:[Creates an S3 bucket, handler for HTTP requests, and API Gateway to Lambda functions.] +// snippet-keyword:[CDK V0.24.1] +// snippet-keyword:[ApiGateway.LambdaIntegration function] +// snippet-keyword:[ApiGateway.RestApi function] +// snippet-keyword:[Bucket.grantReadWrite function] +// snippet-keyword:[Lambda.Function function] +// snippet-keyword:[S3.Bucket function] +// snippet-keyword:[TypeScript] +// snippet-service:[cdk] +// snippet-keyword:[Code Sample] +// snippet-sourcetype:[full-example] +// snippet-sourcedate:[2019-2-8] +// Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// This file is licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, either express or implied. See the License for the specific +// language governing permissions and limitations under the License. +// snippet-start:[cdk.typescript.widget_service] +import cdk = require("@aws-cdk/cdk"); +import apigateway = require("@aws-cdk/aws-apigateway"); +import lambda = require("@aws-cdk/aws-lambda"); +import s3 = require("@aws-cdk/aws-s3"); + +export class WidgetService extends cdk.Construct { + constructor(scope: cdk.Construct, id: string) { + super(scope, id); + + const bucket = new s3.Bucket(this, "WidgetStore"); + + const handler = new lambda.Function(this, "WidgetHandler", { + runtime: lambda.Runtime.NodeJS810, // So we can use async in widget.js + code: lambda.Code.directory("resources"), + handler: "widgets.main", + environment: { + BUCKET: bucket.bucketName + } + }); + + bucket.grantReadWrite(handler); // was: handler.role); + + const api = new apigateway.RestApi(this, "widgets-api", { + restApiName: "Widget Service", + description: "This service serves widgets." + }); + + const getWidgetsIntegration = new apigateway.LambdaIntegration(handler, { + requestTemplates: { "application/json": '{ "statusCode": "200" }' } + }); + + api.root.addMethod("GET", getWidgetsIntegration); // GET / + + // snippet-start:[cdk.typescript.widget_service.wire_up_functions] + const widget = api.root.addResource("{id}"); + + // Add new widget to bucket with: POST /{id} + const postWidgetIntegration = new apigateway.LambdaIntegration(handler); + + // Get a specific widget from bucket with: GET /{id} + const getWidgetIntegration = new apigateway.LambdaIntegration(handler); + + // Remove a specific widget from the bucket with: DELETE /{id} + const deleteWidgetIntegration = new apigateway.LambdaIntegration(handler); + + widget.addMethod("POST", postWidgetIntegration); // POST /{id} + widget.addMethod("GET", getWidgetIntegration); // GET /{id} + widget.addMethod("DELETE", deleteWidgetIntegration); // DELETE /{id} + // snippet-end:[cdk.typescript.widget_service.wire_up_functions] + } +} +// snippet-end:[cdk.typescript.widget_service]