├── .gitignore ├── .npmignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bin └── simple-crud-api.ts ├── cdk.json ├── jest.config.js ├── lambda └── index.js ├── lib └── simple-crud-api-stack.ts ├── package-lock.json ├── package.json ├── test └── simple-crud-api.test.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | !lambda/*.js 4 | *.d.ts 5 | node_modules 6 | .DS_Store 7 | 8 | # CDK asset staging directory 9 | .cdk.staging 10 | cdk.out 11 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to HTTP CRUD API CDK TypeScript project! 2 | 3 | This project contains the CDK code to deploy HTTP CRUD API as demonstrated in https://simple-crud-api.workshop.aws/. The CDK application creates the following resources: 4 | 5 | * API Gateway 6 | * Lambda Function 7 | * DynamoDB Table 8 | 9 | Please run `cdk deploy` to deploy this stack in your AWS account. You can access API using `{ApiGatewayUrl}/items` 10 | 11 | ## Useful commands 12 | 13 | * `npm run build` compile typescript to js 14 | * `npm run watch` watch for changes and compile 15 | * `npm run test` perform the jest unit tests 16 | * `cdk deploy` deploy this stack to your default AWS account/region 17 | * `cdk diff` compare deployed stack with current state 18 | * `cdk synth` emits the synthesized CloudFormation template 19 | 20 | ## Security 21 | 22 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 23 | 24 | ## License 25 | 26 | This library is licensed under the MIT-0 License. See the LICENSE file. 27 | 28 | -------------------------------------------------------------------------------- /bin/simple-crud-api.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | // SPDX-License-Identifier: MIT-0 4 | 5 | import * as cdk from '@aws-cdk/core'; 6 | import { SimpleCrudApiStack } from '../lib/simple-crud-api-stack'; 7 | 8 | const app = new cdk.App(); 9 | new SimpleCrudApiStack(app, 'SimpleCrudApiStack'); 10 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/simple-crud-api.ts", 3 | "context": { 4 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, 5 | "@aws-cdk/core:enableStackNameDuplicates": "true", 6 | "aws-cdk:enableDiffNoFail": "true", 7 | "@aws-cdk/core:stackRelativeExports": "true", 8 | "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, 9 | "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, 10 | "@aws-cdk/aws-kms:defaultKeyPolicies": true, 11 | "@aws-cdk/aws-s3:grantWriteWithoutAcl": true, 12 | "@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount": true, 13 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, 14 | "@aws-cdk/aws-efs:defaultEncryptionAtRest": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: ['/test'], 3 | testMatch: ['**/*.test.ts'], 4 | transform: { 5 | '^.+\\.tsx?$': 'ts-jest' 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /lambda/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | const AWS = require("aws-sdk"); 20 | 21 | const dynamo = new AWS.DynamoDB.DocumentClient(); 22 | 23 | exports.handler = async (event, context) => { 24 | let body; 25 | let statusCode = 200; 26 | const headers = { 27 | "Content-Type": "application/json" 28 | }; 29 | 30 | try { 31 | switch (event.routeKey) { 32 | case "DELETE /items/{id}": 33 | await dynamo 34 | .delete({ 35 | TableName: "http-crud-tutorial-items", 36 | Key: { 37 | id: event.pathParameters.id 38 | } 39 | }) 40 | .promise(); 41 | body = `Deleted item ${event.pathParameters.id}`; 42 | break; 43 | case "GET /items/{id}": 44 | body = await dynamo 45 | .get({ 46 | TableName: "http-crud-tutorial-items", 47 | Key: { 48 | id: event.pathParameters.id 49 | } 50 | }) 51 | .promise(); 52 | break; 53 | case "GET /items": 54 | body = await dynamo.scan({ TableName: "http-crud-tutorial-items" }).promise(); 55 | break; 56 | case "PUT /items": 57 | let requestJSON = JSON.parse(event.body); 58 | await dynamo 59 | .put({ 60 | TableName: "http-crud-tutorial-items", 61 | Item: { 62 | id: requestJSON.id, 63 | price: requestJSON.price, 64 | name: requestJSON.name 65 | } 66 | }) 67 | .promise(); 68 | body = `Put item ${requestJSON.id}`; 69 | break; 70 | default: 71 | throw new Error(`Unsupported route: "${event.routeKey}"`); 72 | } 73 | } catch (err) { 74 | statusCode = 400; 75 | body = err.message; 76 | } finally { 77 | body = JSON.stringify(body); 78 | } 79 | 80 | return { 81 | statusCode, 82 | body, 83 | headers 84 | }; 85 | }; -------------------------------------------------------------------------------- /lib/simple-crud-api-stack.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | import * as cdk from '@aws-cdk/core'; 20 | import * as ddb from '@aws-cdk/aws-dynamodb'; 21 | import * as lambda from '@aws-cdk/aws-lambda'; 22 | import * as apigw from '@aws-cdk/aws-apigatewayv2'; 23 | import {HttpMethod} from '@aws-cdk/aws-apigatewayv2'; 24 | import {LambdaProxyIntegration} from "@aws-cdk/aws-apigatewayv2-integrations"; 25 | 26 | export class SimpleCrudApiStack extends cdk.Stack { 27 | constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { 28 | super(scope, id, props); 29 | 30 | //crate a dynamodb table 31 | const table = new ddb.Table(this, 'SimpleCrudApiTable', { 32 | tableName: 'http-crud-tutorial-items', 33 | partitionKey: {name: 'id', type: ddb.AttributeType.STRING}, 34 | removalPolicy: cdk.RemovalPolicy.DESTROY 35 | }) 36 | 37 | //create a lambda function 38 | const fn = new lambda.Function(this, 'SimpleCrudApiFunction', { 39 | runtime: lambda.Runtime.NODEJS_14_X, 40 | code: lambda.Code.fromAsset('lambda'), 41 | handler: 'index.handler', 42 | functionName: 'http-crud-tutorial-function' 43 | }) 44 | 45 | //give dynamodb read write permission to lambda function 46 | table.grantReadWriteData(fn); 47 | 48 | //create an http api gateway 49 | const api = new apigw.HttpApi(this, 'SimpleCrudApi', { 50 | apiName: 'http-crud-tutorial-api' 51 | }) 52 | 53 | //create lambda proxy 54 | const lambdaProxy = new LambdaProxyIntegration({ 55 | handler: fn 56 | }) 57 | 58 | //add routes for all paths and methods 59 | api.addRoutes({ 60 | path: '/items', 61 | methods: [HttpMethod.GET], 62 | integration: lambdaProxy 63 | }); 64 | 65 | api.addRoutes({ 66 | path: '/items/{id}', 67 | methods: [HttpMethod.GET], 68 | integration: lambdaProxy 69 | }); 70 | 71 | api.addRoutes({ 72 | path: '/items', 73 | methods: [HttpMethod.PUT], 74 | integration: lambdaProxy 75 | }); 76 | 77 | api.addRoutes({ 78 | path: '/items/{id}', 79 | methods: [HttpMethod.DELETE], 80 | integration: lambdaProxy 81 | }); 82 | 83 | new cdk.CfnOutput(this, 'APIGatewayEndpoint', { 84 | exportName: 'APIGatewayEndpoint', 85 | value: api.apiEndpoint, 86 | description: 'The endpoint url of the API Gateway' 87 | }); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-crud-api", 3 | "version": "0.1.0", 4 | "bin": { 5 | "simple-crud-api": "bin/simple-crud-api.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "aws-cdk": "1.103.0", 15 | "@aws-cdk/assert": "1.103.0", 16 | "@types/jest": "^26.0.10", 17 | "@types/node": "10.17.27", 18 | "jest": "^26.4.2", 19 | "ts-jest": "^26.2.0", 20 | "ts-node": "^9.0.0", 21 | "typescript": "~3.9.7" 22 | }, 23 | "dependencies": { 24 | "@aws-cdk/aws-apigatewayv2": "^1.103.0", 25 | "@aws-cdk/aws-apigatewayv2-integrations": "^1.103.0", 26 | "@aws-cdk/aws-dynamodb": "^1.103.0", 27 | "@aws-cdk/aws-lambda": "^1.103.0", 28 | "@aws-cdk/core": "1.103.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/simple-crud-api.test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * SPDX-License-Identifier: MIT-0 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | * software and associated documentation files (the "Software"), to deal in the Software 7 | * without restriction, including without limitation the rights to use, copy, modify, 8 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 12 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 13 | * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 14 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 15 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 16 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | import { expect as expectCDK, haveResource } from '@aws-cdk/assert'; 20 | import * as cdk from '@aws-cdk/core'; 21 | import * as SimpleCrudApi from '../lib/simple-crud-api-stack'; 22 | 23 | test('API Gateway Created', () => { 24 | const app = new cdk.App(); 25 | // WHEN 26 | const stack = new SimpleCrudApi.SimpleCrudApiStack(app, 'MyTestStack'); 27 | // THEN 28 | expectCDK(stack).to(haveResource("AWS::ApiGatewayV2::Api",{ 29 | ProtocolType: 'HTTP' 30 | })); 31 | }); 32 | 33 | test('Lambda Function Created', () => { 34 | const app = new cdk.App(); 35 | // WHEN 36 | const stack = new SimpleCrudApi.SimpleCrudApiStack(app, 'MyTestStack'); 37 | // THEN 38 | expectCDK(stack).to(haveResource("AWS::Lambda::Function",{ 39 | Runtime: 'nodejs14.x' 40 | })); 41 | }); 42 | 43 | test('DynamoDB Table Created', () => { 44 | const app = new cdk.App(); 45 | // WHEN 46 | const stack = new SimpleCrudApi.SimpleCrudApiStack(app, 'MyTestStack'); 47 | // THEN 48 | expectCDK(stack).to(haveResource("AWS::DynamoDB::Table")); 49 | }); 50 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target":"ES2018", 4 | "module": "commonjs", 5 | "lib": ["es2018"], 6 | "declaration": true, 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "strictNullChecks": true, 10 | "noImplicitThis": true, 11 | "alwaysStrict": true, 12 | "noUnusedLocals": false, 13 | "noUnusedParameters": false, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": false, 16 | "inlineSourceMap": true, 17 | "inlineSources": true, 18 | "experimentalDecorators": true, 19 | "strictPropertyInitialization":false, 20 | "typeRoots": ["./node_modules/@types"] 21 | }, 22 | "exclude": ["cdk.out"] 23 | } 24 | --------------------------------------------------------------------------------