├── .nvmrc ├── .serverless ├── getTodo.zip ├── createTodo.zip ├── deleteTodo.zip ├── getAllTodos.zip ├── updateTodo.zip ├── cloudformation-template-create-stack.json ├── cloudformation-template-update-stack.json └── serverless-state.json ├── .npmignore ├── src ├── libs │ ├── handler-resolver.ts │ ├── lambda.ts │ └── api-gateway.ts ├── model │ ├── Todo.ts │ └── index.ts ├── services │ ├── index.ts │ └── todosService.ts └── functions │ └── todo │ ├── index.ts │ └── handler.ts ├── tsconfig.paths.json ├── .gitignore ├── tsconfig.json ├── package.json ├── serverless.ts └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/fermium 2 | -------------------------------------------------------------------------------- /.serverless/getTodo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/aws-serverless-typescript-api/HEAD/.serverless/getTodo.zip -------------------------------------------------------------------------------- /.serverless/createTodo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/aws-serverless-typescript-api/HEAD/.serverless/createTodo.zip -------------------------------------------------------------------------------- /.serverless/deleteTodo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/aws-serverless-typescript-api/HEAD/.serverless/deleteTodo.zip -------------------------------------------------------------------------------- /.serverless/getAllTodos.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/aws-serverless-typescript-api/HEAD/.serverless/getAllTodos.zip -------------------------------------------------------------------------------- /.serverless/updateTodo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/aws-serverless-typescript-api/HEAD/.serverless/updateTodo.zip -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless 7 | 8 | # esbuild directories 9 | .esbuild -------------------------------------------------------------------------------- /src/libs/handler-resolver.ts: -------------------------------------------------------------------------------- 1 | export const handlerPath = (context: string) => { 2 | return `${context.split(process.cwd())[1].substring(1).replace(/\\/g, '/')}` 3 | }; 4 | -------------------------------------------------------------------------------- /src/model/Todo.ts: -------------------------------------------------------------------------------- 1 | export default interface Todo { 2 | todosId: string; 3 | title: string; 4 | description: string; 5 | status: boolean; 6 | createdAt: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/services/index.ts: -------------------------------------------------------------------------------- 1 | import dynamoDBClient from "../model"; 2 | import TodoServerice from "./todosService" 3 | 4 | const todoService = new TodoServerice(dynamoDBClient()); 5 | 6 | export default todoService; -------------------------------------------------------------------------------- /tsconfig.paths.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "@functions/*": ["src/functions/*"], 6 | "@libs/*": ["src/libs/*"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless 7 | 8 | # esbuild directories 9 | .esbuild 10 | 11 | #DynonamoDB local database 12 | .dynamodb -------------------------------------------------------------------------------- /src/libs/lambda.ts: -------------------------------------------------------------------------------- 1 | import middy from "@middy/core" 2 | import middyJsonBodyParser from "@middy/http-json-body-parser" 3 | 4 | export const middyfy = (handler) => { 5 | return middy(handler).use(middyJsonBodyParser()) 6 | } 7 | -------------------------------------------------------------------------------- /src/model/index.ts: -------------------------------------------------------------------------------- 1 | import * as AWS from "aws-sdk"; 2 | import { DocumentClient } from "aws-sdk/clients/dynamodb"; 3 | 4 | const dynamoDBClient = (): DocumentClient => { 5 | if (process.env.IS_OFFLINE) { 6 | return new AWS.DynamoDB.DocumentClient({ 7 | region: "localhost", 8 | endpoint: "http://localhost:5000", 9 | }); 10 | } 11 | 12 | return new AWS.DynamoDB.DocumentClient(); 13 | }; 14 | 15 | export default dynamoDBClient 16 | -------------------------------------------------------------------------------- /src/libs/api-gateway.ts: -------------------------------------------------------------------------------- 1 | import type { APIGatewayProxyEvent, APIGatewayProxyResult, Handler } from "aws-lambda" 2 | import type { FromSchema } from "json-schema-to-ts"; 3 | 4 | type ValidatedAPIGatewayProxyEvent = Omit & { body: FromSchema } 5 | export type ValidatedEventAPIGatewayProxyEvent = Handler, APIGatewayProxyResult> 6 | 7 | export const formatJSONResponse = (response: Record) => { 8 | return { 9 | statusCode: 200, 10 | body: JSON.stringify(response) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.paths.json", 3 | "compilerOptions": { 4 | "lib": ["ESNext"], 5 | "moduleResolution": "node", 6 | "noUnusedLocals": true, 7 | "noUnusedParameters": true, 8 | "removeComments": true, 9 | "sourceMap": true, 10 | "target": "ES2020", 11 | "outDir": "lib" 12 | }, 13 | "include": ["src/**/*.ts", "serverless.ts"], 14 | "exclude": [ 15 | "node_modules/**/*", 16 | ".serverless/**/*", 17 | ".webpack/**/*", 18 | "_warmup/**/*", 19 | ".vscode/**/*" 20 | ], 21 | "ts-node": { 22 | "require": ["tsconfig-paths/register"] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-serverless-api33", 3 | "version": "1.0.0", 4 | "description": "Serverless aws-nodejs-typescript template", 5 | "main": "serverless.ts", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "engines": { 10 | "node": ">=14.15.0" 11 | }, 12 | "dependencies": { 13 | "@middy/core": "^2.5.3", 14 | "@middy/http-json-body-parser": "^2.5.3", 15 | "aws-sdk": "^2.1066.0", 16 | "uuid": "^8.3.2" 17 | }, 18 | "devDependencies": { 19 | "@serverless/typescript": "^3.0.0", 20 | "@types/aws-lambda": "^8.10.71", 21 | "@types/node": "^14.14.25", 22 | "esbuild": "^0.14.11", 23 | "json-schema-to-ts": "^1.5.0", 24 | "serverless": "^3.0.0", 25 | "serverless-esbuild": "^1.23.3", 26 | "ts-node": "^10.4.0", 27 | "tsconfig-paths": "^3.9.0", 28 | "typescript": "^4.1.3" 29 | }, 30 | "author": "The serverless webpack authors (https://github.com/elastic-coders/serverless-webpack)", 31 | "license": "MIT" 32 | } 33 | -------------------------------------------------------------------------------- /src/functions/todo/index.ts: -------------------------------------------------------------------------------- 1 | import { handlerPath } from '@libs/handler-resolver'; 2 | 3 | export const getAllTodos = { 4 | handler: `${handlerPath(__dirname)}/handler.getAllTodos`, 5 | events: [ 6 | { 7 | http: { 8 | method: 'get', 9 | path: 'todo/', 10 | }, 11 | }, 12 | ], 13 | }; 14 | 15 | export const createTodo = { 16 | handler: `${handlerPath(__dirname)}/handler.createTodo`, 17 | events: [ 18 | { 19 | http: { 20 | method: 'post', 21 | path: 'todo', 22 | }, 23 | }, 24 | ], 25 | }; 26 | 27 | export const getTodo = { 28 | handler: `${handlerPath(__dirname)}/handler.getTodo`, 29 | events: [ 30 | { 31 | http: { 32 | method: 'get', 33 | path: 'todo/{id}', 34 | }, 35 | }, 36 | ], 37 | }; 38 | 39 | export const updateTodo = { 40 | handler: `${handlerPath(__dirname)}/handler.updateTodo`, 41 | events: [ 42 | { 43 | http: { 44 | method: 'put', 45 | path: 'todo/{id}', 46 | }, 47 | }, 48 | ], 49 | }; 50 | 51 | export const deleteTodo = { 52 | handler: `${handlerPath(__dirname)}/handler.deleteTodo`, 53 | events: [ 54 | { 55 | http: { 56 | method: 'delete', 57 | path: 'todo/{id}', 58 | }, 59 | }, 60 | ], 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /src/services/todosService.ts: -------------------------------------------------------------------------------- 1 | import { DocumentClient } from "aws-sdk/clients/dynamodb"; 2 | 3 | import Todo from "../model/Todo"; 4 | 5 | export default class TodoServerice { 6 | 7 | private Tablename: string = "TodosTable"; 8 | 9 | constructor(private docClient: DocumentClient) { } 10 | 11 | async getAllTodos(): Promise { 12 | const todos = await this.docClient.scan({ 13 | TableName: this.Tablename, 14 | }).promise() 15 | return todos.Items as Todo[]; 16 | } 17 | 18 | async createTodo(todo: Todo): Promise { 19 | await this.docClient.put({ 20 | TableName: this.Tablename, 21 | Item: todo 22 | }).promise() 23 | return todo as Todo; 24 | 25 | } 26 | 27 | async getTodo(id: string): Promise { 28 | 29 | const todo = await this.docClient.get({ 30 | TableName: this.Tablename, 31 | Key: { 32 | todosId: id 33 | } 34 | }).promise() 35 | if (!todo.Item) { 36 | throw new Error("Id does not exit"); 37 | } 38 | return todo.Item as Todo; 39 | 40 | } 41 | 42 | async updateTodo(id: string, todo: Partial): Promise { 43 | const updated = await this.docClient 44 | .update({ 45 | TableName: this.Tablename, 46 | Key: { todosId: id }, 47 | UpdateExpression: 48 | "set #status = :status", 49 | ExpressionAttributeNames: { 50 | "#status": "status", 51 | }, 52 | ExpressionAttributeValues: { 53 | ":status": todo.status, 54 | }, 55 | ReturnValues: "ALL_NEW", 56 | }) 57 | .promise(); 58 | 59 | return updated.Attributes as Todo; 60 | } 61 | 62 | async deleteTodo(id: string): Promise { 63 | return await this.docClient.delete({ 64 | TableName: this.Tablename, 65 | Key: { 66 | todosId: id 67 | } 68 | }).promise() 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /.serverless/cloudformation-template-create-stack.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "The AWS CloudFormation template for this Serverless application", 4 | "Resources": { 5 | "ServerlessDeploymentBucket": { 6 | "Type": "AWS::S3::Bucket", 7 | "Properties": { 8 | "BucketEncryption": { 9 | "ServerSideEncryptionConfiguration": [ 10 | { 11 | "ServerSideEncryptionByDefault": { 12 | "SSEAlgorithm": "AES256" 13 | } 14 | } 15 | ] 16 | } 17 | } 18 | }, 19 | "ServerlessDeploymentBucketPolicy": { 20 | "Type": "AWS::S3::BucketPolicy", 21 | "Properties": { 22 | "Bucket": { 23 | "Ref": "ServerlessDeploymentBucket" 24 | }, 25 | "PolicyDocument": { 26 | "Statement": [ 27 | { 28 | "Action": "s3:*", 29 | "Effect": "Deny", 30 | "Principal": "*", 31 | "Resource": [ 32 | { 33 | "Fn::Join": [ 34 | "", 35 | [ 36 | "arn:", 37 | { 38 | "Ref": "AWS::Partition" 39 | }, 40 | ":s3:::", 41 | { 42 | "Ref": "ServerlessDeploymentBucket" 43 | }, 44 | "/*" 45 | ] 46 | ] 47 | }, 48 | { 49 | "Fn::Join": [ 50 | "", 51 | [ 52 | "arn:", 53 | { 54 | "Ref": "AWS::Partition" 55 | }, 56 | ":s3:::", 57 | { 58 | "Ref": "ServerlessDeploymentBucket" 59 | } 60 | ] 61 | ] 62 | } 63 | ], 64 | "Condition": { 65 | "Bool": { 66 | "aws:SecureTransport": false 67 | } 68 | } 69 | } 70 | ] 71 | } 72 | } 73 | } 74 | }, 75 | "Outputs": { 76 | "ServerlessDeploymentBucketName": { 77 | "Value": { 78 | "Ref": "ServerlessDeploymentBucket" 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /serverless.ts: -------------------------------------------------------------------------------- 1 | import type { AWS } from '@serverless/typescript'; 2 | 3 | import { createTodo, getTodo, getAllTodos, updateTodo, deleteTodo } from '@functions/todo'; 4 | 5 | const serverlessConfiguration: AWS = { 6 | service: 'aws-serverless-typescript-api', 7 | frameworkVersion: '3', 8 | plugins: ['serverless-esbuild', 'serverless-offline', 'serverless-dynamodb-local'], 9 | provider: { 10 | name: 'aws', 11 | runtime: 'nodejs14.x', 12 | apiGateway: { 13 | minimumCompressionSize: 1024, 14 | shouldStartNameWithService: true, 15 | }, 16 | environment: { 17 | AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1', 18 | NODE_OPTIONS: '--enable-source-maps --stack-trace-limit=1000', 19 | }, 20 | iam: { 21 | role: { 22 | statements: [{ 23 | Effect: "Allow", 24 | Action: [ 25 | "dynamodb:DescribeTable", 26 | "dynamodb:Query", 27 | "dynamodb:Scan", 28 | "dynamodb:GetItem", 29 | "dynamodb:PutItem", 30 | "dynamodb:UpdateItem", 31 | "dynamodb:DeleteItem", 32 | ], 33 | Resource: "arn:aws:dynamodb:us-west-2:*:table/TodosTable", 34 | }], 35 | }, 36 | 37 | }, 38 | }, 39 | // import the function via paths 40 | functions: { getAllTodos, createTodo, getTodo, updateTodo, deleteTodo }, 41 | package: { individually: true }, 42 | custom:{ 43 | esbuild: { 44 | bundle: true, 45 | minify: false, 46 | sourcemap: true, 47 | exclude: ['aws-sdk'], 48 | target: 'node14', 49 | define: { 'require.resolve': undefined }, 50 | platform: 'node', 51 | concurrency: 10, 52 | }, 53 | dynamodb:{ 54 | start:{ 55 | port: 5000, 56 | inMemory: true, 57 | migrate: true, 58 | }, 59 | stages: "dev" 60 | } 61 | }, 62 | resources: { 63 | Resources: { 64 | TodosTable: { 65 | Type: "AWS::DynamoDB::Table", 66 | Properties: { 67 | TableName: "TodosTable", 68 | AttributeDefinitions: [{ 69 | AttributeName: "todosId", 70 | AttributeType: "S", 71 | }], 72 | KeySchema: [{ 73 | AttributeName: "todosId", 74 | KeyType: "HASH" 75 | }], 76 | ProvisionedThroughput: { 77 | ReadCapacityUnits: 1, 78 | WriteCapacityUnits: 1 79 | }, 80 | 81 | } 82 | } 83 | } 84 | } 85 | }; 86 | 87 | module.exports = serverlessConfiguration; 88 | -------------------------------------------------------------------------------- /src/functions/todo/handler.ts: -------------------------------------------------------------------------------- 1 | import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda"; 2 | import { formatJSONResponse } from '@libs/api-gateway'; 3 | import { middyfy } from '@libs/lambda'; 4 | import todosService from '../../services' 5 | 6 | import { v4 } from "uuid"; 7 | 8 | export const getAllTodos = middyfy(async (): Promise => { 9 | const todos = await todosService.getAllTodos(); 10 | return formatJSONResponse({ 11 | todos 12 | }) 13 | }) 14 | 15 | export const createTodo = middyfy(async (event: APIGatewayProxyEvent): Promise => { 16 | try { 17 | const id = v4(); 18 | const todo = await todosService.createTodo({ 19 | todosId: id, 20 | title: event.body.title, 21 | description: event.body.description, 22 | createdAt: new Date().toISOString(), 23 | status: false 24 | }) 25 | return formatJSONResponse({ 26 | todo 27 | }); 28 | } catch (e) { 29 | return formatJSONResponse({ 30 | status: 500, 31 | message: e 32 | }); 33 | } 34 | }) 35 | 36 | export const getTodo = middyfy(async (event: APIGatewayProxyEvent): Promise => { 37 | const id = event.pathParameters.id; 38 | try { 39 | const todo = await todosService.getTodo(id) 40 | return formatJSONResponse({ 41 | todo, id 42 | }); 43 | } catch (e) { 44 | return formatJSONResponse({ 45 | status: 500, 46 | message: e 47 | }); 48 | } 49 | }) 50 | 51 | export const updateTodo = middyfy(async (event: APIGatewayProxyEvent): Promise => { 52 | const id = event.pathParameters.id; 53 | try { 54 | const todo = await todosService.updateTodo(id, { status: event.body.status }) 55 | return formatJSONResponse({ 56 | todo, id 57 | }); 58 | } catch (e) { 59 | return formatJSONResponse({ 60 | status: 500, 61 | message: e 62 | }); 63 | } 64 | }) 65 | 66 | export const deleteTodo = middyfy(async (event: APIGatewayProxyEvent): Promise => { 67 | const id = event.pathParameters.id; 68 | try { 69 | const todo = await todosService.deleteTodo(id) 70 | return formatJSONResponse({ 71 | todo, id 72 | }); 73 | } catch (e) { 74 | return formatJSONResponse({ 75 | status: 500, 76 | message: e 77 | }); 78 | } 79 | }) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serverless - AWS Node.js Typescript 2 | 3 | This project has been generated using the `aws-nodejs-typescript` template from the [Serverless framework](https://www.serverless.com/). 4 | 5 | For detailed instructions, please refer to the [documentation](https://www.serverless.com/framework/docs/providers/aws/). 6 | 7 | ## Installation/deployment instructions 8 | 9 | Depending on your preferred package manager, follow the instructions below to deploy your project. 10 | 11 | > **Requirements**: NodeJS `lts/fermium (v.14.15.0)`. If you're using [nvm](https://github.com/nvm-sh/nvm), run `nvm use` to ensure you're using the same Node version in local and in your lambda's runtime. 12 | 13 | ### Using NPM 14 | 15 | - Run `npm i` to install the project dependencies 16 | - Run `npx sls deploy` to deploy this stack to AWS 17 | 18 | ### Using Yarn 19 | 20 | - Run `yarn` to install the project dependencies 21 | - Run `yarn sls deploy` to deploy this stack to AWS 22 | 23 | ## Test your service 24 | 25 | This template contains a single lambda function triggered by an HTTP request made on the provisioned API Gateway REST API `/hello` route with `POST` method. The request body must be provided as `application/json`. The body structure is tested by API Gateway against `src/functions/hello/schema.ts` JSON-Schema definition: it must contain the `name` property. 26 | 27 | - requesting any other path than `/hello` with any other method than `POST` will result in API Gateway returning a `403` HTTP error code 28 | - sending a `POST` request to `/hello` with a payload **not** containing a string property named `name` will result in API Gateway returning a `400` HTTP error code 29 | - sending a `POST` request to `/hello` with a payload containing a string property named `name` will result in API Gateway returning a `200` HTTP status code with a message saluting the provided name and the detailed event processed by the lambda 30 | 31 | > :warning: As is, this template, once deployed, opens a **public** endpoint within your AWS account resources. Anybody with the URL can actively execute the API Gateway endpoint and the corresponding lambda. You should protect this endpoint with the authentication method of your choice. 32 | 33 | ### Locally 34 | 35 | In order to test the hello function locally, run the following command: 36 | 37 | - `npx sls invoke local -f hello --path src/functions/hello/mock.json` if you're using NPM 38 | - `yarn sls invoke local -f hello --path src/functions/hello/mock.json` if you're using Yarn 39 | 40 | Check the [sls invoke local command documentation](https://www.serverless.com/framework/docs/providers/aws/cli-reference/invoke-local/) for more information. 41 | 42 | ### Remotely 43 | 44 | Copy and replace your `url` - found in Serverless `deploy` command output - and `name` parameter in the following `curl` command in your terminal or in Postman to test your newly deployed application. 45 | 46 | ``` 47 | curl --location --request POST 'https://myApiEndpoint/dev/hello' \ 48 | --header 'Content-Type: application/json' \ 49 | --data-raw '{ 50 | "name": "Frederic" 51 | }' 52 | ``` 53 | 54 | ## Template features 55 | 56 | ### Project structure 57 | 58 | The project code base is mainly located within the `src` folder. This folder is divided in: 59 | 60 | - `functions` - containing code base and configuration for your lambda functions 61 | - `libs` - containing shared code base between your lambdas 62 | 63 | ``` 64 | . 65 | ├── src 66 | │ ├── functions # Lambda configuration and source code folder 67 | │ │ ├── hello 68 | │ │ │ ├── handler.ts # `Hello` lambda source code 69 | │ │ │ ├── index.ts # `Hello` lambda Serverless configuration 70 | │ │ │ ├── mock.json # `Hello` lambda input parameter, if any, for local invocation 71 | │ │ │ └── schema.ts # `Hello` lambda input event JSON-Schema 72 | │ │ │ 73 | │ │ └── index.ts # Import/export of all lambda configurations 74 | │ │ 75 | │ └── libs # Lambda shared code 76 | │ └── apiGateway.ts # API Gateway specific helpers 77 | │ └── handlerResolver.ts # Sharable library for resolving lambda handlers 78 | │ └── lambda.ts # Lambda middleware 79 | │ 80 | ├── package.json 81 | ├── serverless.ts # Serverless service file 82 | ├── tsconfig.json # Typescript compiler configuration 83 | ├── tsconfig.paths.json # Typescript paths 84 | └── webpack.config.js # Webpack configuration 85 | ``` 86 | 87 | ### 3rd party libraries 88 | 89 | - [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts) - uses JSON-Schema definitions used by API Gateway for HTTP request validation to statically generate TypeScript types in your lambda's handler code base 90 | - [middy](https://github.com/middyjs/middy) - middleware engine for Node.Js lambda. This template uses [http-json-body-parser](https://github.com/middyjs/middy/tree/master/packages/http-json-body-parser) to convert API Gateway `event.body` property, originally passed as a stringified JSON, to its corresponding parsed object 91 | - [@serverless/typescript](https://github.com/serverless/typescript) - provides up-to-date TypeScript definitions for your `serverless.ts` service file 92 | 93 | ### Advanced usage 94 | 95 | Any tsconfig.json can be used, but if you do, set the environment variable `TS_NODE_CONFIG` for building the application, eg `TS_NODE_CONFIG=./tsconfig.app.json npx serverless webpack` 96 | -------------------------------------------------------------------------------- /.serverless/cloudformation-template-update-stack.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "The AWS CloudFormation template for this Serverless application", 4 | "Resources": { 5 | "ServerlessDeploymentBucket": { 6 | "Type": "AWS::S3::Bucket", 7 | "Properties": { 8 | "BucketEncryption": { 9 | "ServerSideEncryptionConfiguration": [ 10 | { 11 | "ServerSideEncryptionByDefault": { 12 | "SSEAlgorithm": "AES256" 13 | } 14 | } 15 | ] 16 | } 17 | } 18 | }, 19 | "ServerlessDeploymentBucketPolicy": { 20 | "Type": "AWS::S3::BucketPolicy", 21 | "Properties": { 22 | "Bucket": { 23 | "Ref": "ServerlessDeploymentBucket" 24 | }, 25 | "PolicyDocument": { 26 | "Statement": [ 27 | { 28 | "Action": "s3:*", 29 | "Effect": "Deny", 30 | "Principal": "*", 31 | "Resource": [ 32 | { 33 | "Fn::Join": [ 34 | "", 35 | [ 36 | "arn:", 37 | { 38 | "Ref": "AWS::Partition" 39 | }, 40 | ":s3:::", 41 | { 42 | "Ref": "ServerlessDeploymentBucket" 43 | }, 44 | "/*" 45 | ] 46 | ] 47 | }, 48 | { 49 | "Fn::Join": [ 50 | "", 51 | [ 52 | "arn:", 53 | { 54 | "Ref": "AWS::Partition" 55 | }, 56 | ":s3:::", 57 | { 58 | "Ref": "ServerlessDeploymentBucket" 59 | } 60 | ] 61 | ] 62 | } 63 | ], 64 | "Condition": { 65 | "Bool": { 66 | "aws:SecureTransport": false 67 | } 68 | } 69 | } 70 | ] 71 | } 72 | } 73 | }, 74 | "GetAllTodosLogGroup": { 75 | "Type": "AWS::Logs::LogGroup", 76 | "Properties": { 77 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-getAllTodos" 78 | } 79 | }, 80 | "CreateTodoLogGroup": { 81 | "Type": "AWS::Logs::LogGroup", 82 | "Properties": { 83 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-createTodo" 84 | } 85 | }, 86 | "GetTodoLogGroup": { 87 | "Type": "AWS::Logs::LogGroup", 88 | "Properties": { 89 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-getTodo" 90 | } 91 | }, 92 | "UpdateTodoLogGroup": { 93 | "Type": "AWS::Logs::LogGroup", 94 | "Properties": { 95 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-updateTodo" 96 | } 97 | }, 98 | "DeleteTodoLogGroup": { 99 | "Type": "AWS::Logs::LogGroup", 100 | "Properties": { 101 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-deleteTodo" 102 | } 103 | }, 104 | "IamRoleLambdaExecution": { 105 | "Type": "AWS::IAM::Role", 106 | "Properties": { 107 | "AssumeRolePolicyDocument": { 108 | "Version": "2012-10-17", 109 | "Statement": [ 110 | { 111 | "Effect": "Allow", 112 | "Principal": { 113 | "Service": [ 114 | "lambda.amazonaws.com" 115 | ] 116 | }, 117 | "Action": [ 118 | "sts:AssumeRole" 119 | ] 120 | } 121 | ] 122 | }, 123 | "Policies": [ 124 | { 125 | "PolicyName": { 126 | "Fn::Join": [ 127 | "-", 128 | [ 129 | "aws-serverless-typescript-api", 130 | "dev", 131 | "lambda" 132 | ] 133 | ] 134 | }, 135 | "PolicyDocument": { 136 | "Version": "2012-10-17", 137 | "Statement": [ 138 | { 139 | "Effect": "Allow", 140 | "Action": [ 141 | "logs:CreateLogStream", 142 | "logs:CreateLogGroup" 143 | ], 144 | "Resource": [ 145 | { 146 | "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-serverless-typescript-api-dev*:*" 147 | } 148 | ] 149 | }, 150 | { 151 | "Effect": "Allow", 152 | "Action": [ 153 | "logs:PutLogEvents" 154 | ], 155 | "Resource": [ 156 | { 157 | "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-serverless-typescript-api-dev*:*:*" 158 | } 159 | ] 160 | }, 161 | { 162 | "Effect": "Allow", 163 | "Action": [ 164 | "dynamodb:DescribeTable", 165 | "dynamodb:Query", 166 | "dynamodb:Scan", 167 | "dynamodb:GetItem", 168 | "dynamodb:PutItem", 169 | "dynamodb:UpdateItem", 170 | "dynamodb:DeleteItem" 171 | ], 172 | "Resource": "arn:aws:dynamodb:us-west-2:*:table/TodosTable2" 173 | } 174 | ] 175 | } 176 | } 177 | ], 178 | "Path": "/", 179 | "RoleName": { 180 | "Fn::Join": [ 181 | "-", 182 | [ 183 | "aws-serverless-typescript-api", 184 | "dev", 185 | { 186 | "Ref": "AWS::Region" 187 | }, 188 | "lambdaRole" 189 | ] 190 | ] 191 | } 192 | } 193 | }, 194 | "GetAllTodosLambdaFunction": { 195 | "Type": "AWS::Lambda::Function", 196 | "Properties": { 197 | "Code": { 198 | "S3Bucket": { 199 | "Ref": "ServerlessDeploymentBucket" 200 | }, 201 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/getAllTodos.zip" 202 | }, 203 | "Handler": "src/functions/todo/handler.getAllTodos", 204 | "Runtime": "nodejs14.x", 205 | "FunctionName": "aws-serverless-typescript-api-dev-getAllTodos", 206 | "MemorySize": 1024, 207 | "Timeout": 6, 208 | "Environment": { 209 | "Variables": { 210 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 211 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 212 | } 213 | }, 214 | "Role": { 215 | "Fn::GetAtt": [ 216 | "IamRoleLambdaExecution", 217 | "Arn" 218 | ] 219 | } 220 | }, 221 | "DependsOn": [ 222 | "GetAllTodosLogGroup" 223 | ] 224 | }, 225 | "CreateTodoLambdaFunction": { 226 | "Type": "AWS::Lambda::Function", 227 | "Properties": { 228 | "Code": { 229 | "S3Bucket": { 230 | "Ref": "ServerlessDeploymentBucket" 231 | }, 232 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/createTodo.zip" 233 | }, 234 | "Handler": "src/functions/todo/handler.createTodo", 235 | "Runtime": "nodejs14.x", 236 | "FunctionName": "aws-serverless-typescript-api-dev-createTodo", 237 | "MemorySize": 1024, 238 | "Timeout": 6, 239 | "Environment": { 240 | "Variables": { 241 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 242 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 243 | } 244 | }, 245 | "Role": { 246 | "Fn::GetAtt": [ 247 | "IamRoleLambdaExecution", 248 | "Arn" 249 | ] 250 | } 251 | }, 252 | "DependsOn": [ 253 | "CreateTodoLogGroup" 254 | ] 255 | }, 256 | "GetTodoLambdaFunction": { 257 | "Type": "AWS::Lambda::Function", 258 | "Properties": { 259 | "Code": { 260 | "S3Bucket": { 261 | "Ref": "ServerlessDeploymentBucket" 262 | }, 263 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/getTodo.zip" 264 | }, 265 | "Handler": "src/functions/todo/handler.getTodo", 266 | "Runtime": "nodejs14.x", 267 | "FunctionName": "aws-serverless-typescript-api-dev-getTodo", 268 | "MemorySize": 1024, 269 | "Timeout": 6, 270 | "Environment": { 271 | "Variables": { 272 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 273 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 274 | } 275 | }, 276 | "Role": { 277 | "Fn::GetAtt": [ 278 | "IamRoleLambdaExecution", 279 | "Arn" 280 | ] 281 | } 282 | }, 283 | "DependsOn": [ 284 | "GetTodoLogGroup" 285 | ] 286 | }, 287 | "UpdateTodoLambdaFunction": { 288 | "Type": "AWS::Lambda::Function", 289 | "Properties": { 290 | "Code": { 291 | "S3Bucket": { 292 | "Ref": "ServerlessDeploymentBucket" 293 | }, 294 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/updateTodo.zip" 295 | }, 296 | "Handler": "src/functions/todo/handler.updateTodo", 297 | "Runtime": "nodejs14.x", 298 | "FunctionName": "aws-serverless-typescript-api-dev-updateTodo", 299 | "MemorySize": 1024, 300 | "Timeout": 6, 301 | "Environment": { 302 | "Variables": { 303 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 304 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 305 | } 306 | }, 307 | "Role": { 308 | "Fn::GetAtt": [ 309 | "IamRoleLambdaExecution", 310 | "Arn" 311 | ] 312 | } 313 | }, 314 | "DependsOn": [ 315 | "UpdateTodoLogGroup" 316 | ] 317 | }, 318 | "DeleteTodoLambdaFunction": { 319 | "Type": "AWS::Lambda::Function", 320 | "Properties": { 321 | "Code": { 322 | "S3Bucket": { 323 | "Ref": "ServerlessDeploymentBucket" 324 | }, 325 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/deleteTodo.zip" 326 | }, 327 | "Handler": "src/functions/todo/handler.deleteTodo", 328 | "Runtime": "nodejs14.x", 329 | "FunctionName": "aws-serverless-typescript-api-dev-deleteTodo", 330 | "MemorySize": 1024, 331 | "Timeout": 6, 332 | "Environment": { 333 | "Variables": { 334 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 335 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 336 | } 337 | }, 338 | "Role": { 339 | "Fn::GetAtt": [ 340 | "IamRoleLambdaExecution", 341 | "Arn" 342 | ] 343 | } 344 | }, 345 | "DependsOn": [ 346 | "DeleteTodoLogGroup" 347 | ] 348 | }, 349 | "GetAllTodosLambdaVersionp0CdOAiYHjhgPjyDDwjPIiT67HNeYsAeWdmrnmD0": { 350 | "Type": "AWS::Lambda::Version", 351 | "DeletionPolicy": "Retain", 352 | "Properties": { 353 | "FunctionName": { 354 | "Ref": "GetAllTodosLambdaFunction" 355 | }, 356 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 357 | } 358 | }, 359 | "CreateTodoLambdaVersionXASP5192wCR21kDeCZSW2spvZzTajrBSkq3BwEdYhU": { 360 | "Type": "AWS::Lambda::Version", 361 | "DeletionPolicy": "Retain", 362 | "Properties": { 363 | "FunctionName": { 364 | "Ref": "CreateTodoLambdaFunction" 365 | }, 366 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 367 | } 368 | }, 369 | "GetTodoLambdaVersionE8UrAWLkP0Xh97xb7Pk6lktuR6dCIdZy7MEiRC18zA": { 370 | "Type": "AWS::Lambda::Version", 371 | "DeletionPolicy": "Retain", 372 | "Properties": { 373 | "FunctionName": { 374 | "Ref": "GetTodoLambdaFunction" 375 | }, 376 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 377 | } 378 | }, 379 | "UpdateTodoLambdaVersionVDAD1c1Pj3YQdlUHsBhnKhoPlfMmuYkH5Agsqso": { 380 | "Type": "AWS::Lambda::Version", 381 | "DeletionPolicy": "Retain", 382 | "Properties": { 383 | "FunctionName": { 384 | "Ref": "UpdateTodoLambdaFunction" 385 | }, 386 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 387 | } 388 | }, 389 | "DeleteTodoLambdaVersionlgAsU51djBs58IU60SiryGSQF1gcQovPswjRv2Hvi4": { 390 | "Type": "AWS::Lambda::Version", 391 | "DeletionPolicy": "Retain", 392 | "Properties": { 393 | "FunctionName": { 394 | "Ref": "DeleteTodoLambdaFunction" 395 | }, 396 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 397 | } 398 | }, 399 | "ApiGatewayRestApi": { 400 | "Type": "AWS::ApiGateway::RestApi", 401 | "Properties": { 402 | "Name": "aws-serverless-typescript-api-dev", 403 | "EndpointConfiguration": { 404 | "Types": [ 405 | "EDGE" 406 | ] 407 | }, 408 | "Policy": "", 409 | "MinimumCompressionSize": 1024 410 | } 411 | }, 412 | "ApiGatewayResourceTodo": { 413 | "Type": "AWS::ApiGateway::Resource", 414 | "Properties": { 415 | "ParentId": { 416 | "Fn::GetAtt": [ 417 | "ApiGatewayRestApi", 418 | "RootResourceId" 419 | ] 420 | }, 421 | "PathPart": "todo", 422 | "RestApiId": { 423 | "Ref": "ApiGatewayRestApi" 424 | } 425 | } 426 | }, 427 | "ApiGatewayResourceTodoIdVar": { 428 | "Type": "AWS::ApiGateway::Resource", 429 | "Properties": { 430 | "ParentId": { 431 | "Ref": "ApiGatewayResourceTodo" 432 | }, 433 | "PathPart": "{id}", 434 | "RestApiId": { 435 | "Ref": "ApiGatewayRestApi" 436 | } 437 | } 438 | }, 439 | "ApiGatewayMethodTodoGet": { 440 | "Type": "AWS::ApiGateway::Method", 441 | "Properties": { 442 | "HttpMethod": "GET", 443 | "RequestParameters": {}, 444 | "ResourceId": { 445 | "Ref": "ApiGatewayResourceTodo" 446 | }, 447 | "RestApiId": { 448 | "Ref": "ApiGatewayRestApi" 449 | }, 450 | "ApiKeyRequired": false, 451 | "AuthorizationType": "NONE", 452 | "Integration": { 453 | "IntegrationHttpMethod": "POST", 454 | "Type": "AWS_PROXY", 455 | "Uri": { 456 | "Fn::Join": [ 457 | "", 458 | [ 459 | "arn:", 460 | { 461 | "Ref": "AWS::Partition" 462 | }, 463 | ":apigateway:", 464 | { 465 | "Ref": "AWS::Region" 466 | }, 467 | ":lambda:path/2015-03-31/functions/", 468 | { 469 | "Fn::GetAtt": [ 470 | "GetAllTodosLambdaFunction", 471 | "Arn" 472 | ] 473 | }, 474 | "/invocations" 475 | ] 476 | ] 477 | } 478 | }, 479 | "MethodResponses": [] 480 | }, 481 | "DependsOn": [ 482 | "GetAllTodosLambdaPermissionApiGateway" 483 | ] 484 | }, 485 | "ApiGatewayMethodTodoPost": { 486 | "Type": "AWS::ApiGateway::Method", 487 | "Properties": { 488 | "HttpMethod": "POST", 489 | "RequestParameters": {}, 490 | "ResourceId": { 491 | "Ref": "ApiGatewayResourceTodo" 492 | }, 493 | "RestApiId": { 494 | "Ref": "ApiGatewayRestApi" 495 | }, 496 | "ApiKeyRequired": false, 497 | "AuthorizationType": "NONE", 498 | "Integration": { 499 | "IntegrationHttpMethod": "POST", 500 | "Type": "AWS_PROXY", 501 | "Uri": { 502 | "Fn::Join": [ 503 | "", 504 | [ 505 | "arn:", 506 | { 507 | "Ref": "AWS::Partition" 508 | }, 509 | ":apigateway:", 510 | { 511 | "Ref": "AWS::Region" 512 | }, 513 | ":lambda:path/2015-03-31/functions/", 514 | { 515 | "Fn::GetAtt": [ 516 | "CreateTodoLambdaFunction", 517 | "Arn" 518 | ] 519 | }, 520 | "/invocations" 521 | ] 522 | ] 523 | } 524 | }, 525 | "MethodResponses": [] 526 | }, 527 | "DependsOn": [ 528 | "CreateTodoLambdaPermissionApiGateway" 529 | ] 530 | }, 531 | "ApiGatewayMethodTodoIdVarGet": { 532 | "Type": "AWS::ApiGateway::Method", 533 | "Properties": { 534 | "HttpMethod": "GET", 535 | "RequestParameters": {}, 536 | "ResourceId": { 537 | "Ref": "ApiGatewayResourceTodoIdVar" 538 | }, 539 | "RestApiId": { 540 | "Ref": "ApiGatewayRestApi" 541 | }, 542 | "ApiKeyRequired": false, 543 | "AuthorizationType": "NONE", 544 | "Integration": { 545 | "IntegrationHttpMethod": "POST", 546 | "Type": "AWS_PROXY", 547 | "Uri": { 548 | "Fn::Join": [ 549 | "", 550 | [ 551 | "arn:", 552 | { 553 | "Ref": "AWS::Partition" 554 | }, 555 | ":apigateway:", 556 | { 557 | "Ref": "AWS::Region" 558 | }, 559 | ":lambda:path/2015-03-31/functions/", 560 | { 561 | "Fn::GetAtt": [ 562 | "GetTodoLambdaFunction", 563 | "Arn" 564 | ] 565 | }, 566 | "/invocations" 567 | ] 568 | ] 569 | } 570 | }, 571 | "MethodResponses": [] 572 | }, 573 | "DependsOn": [ 574 | "GetTodoLambdaPermissionApiGateway" 575 | ] 576 | }, 577 | "ApiGatewayMethodTodoIdVarPut": { 578 | "Type": "AWS::ApiGateway::Method", 579 | "Properties": { 580 | "HttpMethod": "PUT", 581 | "RequestParameters": {}, 582 | "ResourceId": { 583 | "Ref": "ApiGatewayResourceTodoIdVar" 584 | }, 585 | "RestApiId": { 586 | "Ref": "ApiGatewayRestApi" 587 | }, 588 | "ApiKeyRequired": false, 589 | "AuthorizationType": "NONE", 590 | "Integration": { 591 | "IntegrationHttpMethod": "POST", 592 | "Type": "AWS_PROXY", 593 | "Uri": { 594 | "Fn::Join": [ 595 | "", 596 | [ 597 | "arn:", 598 | { 599 | "Ref": "AWS::Partition" 600 | }, 601 | ":apigateway:", 602 | { 603 | "Ref": "AWS::Region" 604 | }, 605 | ":lambda:path/2015-03-31/functions/", 606 | { 607 | "Fn::GetAtt": [ 608 | "UpdateTodoLambdaFunction", 609 | "Arn" 610 | ] 611 | }, 612 | "/invocations" 613 | ] 614 | ] 615 | } 616 | }, 617 | "MethodResponses": [] 618 | }, 619 | "DependsOn": [ 620 | "UpdateTodoLambdaPermissionApiGateway" 621 | ] 622 | }, 623 | "ApiGatewayMethodTodoIdVarDelete": { 624 | "Type": "AWS::ApiGateway::Method", 625 | "Properties": { 626 | "HttpMethod": "DELETE", 627 | "RequestParameters": {}, 628 | "ResourceId": { 629 | "Ref": "ApiGatewayResourceTodoIdVar" 630 | }, 631 | "RestApiId": { 632 | "Ref": "ApiGatewayRestApi" 633 | }, 634 | "ApiKeyRequired": false, 635 | "AuthorizationType": "NONE", 636 | "Integration": { 637 | "IntegrationHttpMethod": "POST", 638 | "Type": "AWS_PROXY", 639 | "Uri": { 640 | "Fn::Join": [ 641 | "", 642 | [ 643 | "arn:", 644 | { 645 | "Ref": "AWS::Partition" 646 | }, 647 | ":apigateway:", 648 | { 649 | "Ref": "AWS::Region" 650 | }, 651 | ":lambda:path/2015-03-31/functions/", 652 | { 653 | "Fn::GetAtt": [ 654 | "DeleteTodoLambdaFunction", 655 | "Arn" 656 | ] 657 | }, 658 | "/invocations" 659 | ] 660 | ] 661 | } 662 | }, 663 | "MethodResponses": [] 664 | }, 665 | "DependsOn": [ 666 | "DeleteTodoLambdaPermissionApiGateway" 667 | ] 668 | }, 669 | "ApiGatewayDeployment1643643477891": { 670 | "Type": "AWS::ApiGateway::Deployment", 671 | "Properties": { 672 | "RestApiId": { 673 | "Ref": "ApiGatewayRestApi" 674 | }, 675 | "StageName": "dev" 676 | }, 677 | "DependsOn": [ 678 | "ApiGatewayMethodTodoGet", 679 | "ApiGatewayMethodTodoPost", 680 | "ApiGatewayMethodTodoIdVarGet", 681 | "ApiGatewayMethodTodoIdVarPut", 682 | "ApiGatewayMethodTodoIdVarDelete" 683 | ] 684 | }, 685 | "GetAllTodosLambdaPermissionApiGateway": { 686 | "Type": "AWS::Lambda::Permission", 687 | "Properties": { 688 | "FunctionName": { 689 | "Fn::GetAtt": [ 690 | "GetAllTodosLambdaFunction", 691 | "Arn" 692 | ] 693 | }, 694 | "Action": "lambda:InvokeFunction", 695 | "Principal": "apigateway.amazonaws.com", 696 | "SourceArn": { 697 | "Fn::Join": [ 698 | "", 699 | [ 700 | "arn:", 701 | { 702 | "Ref": "AWS::Partition" 703 | }, 704 | ":execute-api:", 705 | { 706 | "Ref": "AWS::Region" 707 | }, 708 | ":", 709 | { 710 | "Ref": "AWS::AccountId" 711 | }, 712 | ":", 713 | { 714 | "Ref": "ApiGatewayRestApi" 715 | }, 716 | "/*/*" 717 | ] 718 | ] 719 | } 720 | } 721 | }, 722 | "CreateTodoLambdaPermissionApiGateway": { 723 | "Type": "AWS::Lambda::Permission", 724 | "Properties": { 725 | "FunctionName": { 726 | "Fn::GetAtt": [ 727 | "CreateTodoLambdaFunction", 728 | "Arn" 729 | ] 730 | }, 731 | "Action": "lambda:InvokeFunction", 732 | "Principal": "apigateway.amazonaws.com", 733 | "SourceArn": { 734 | "Fn::Join": [ 735 | "", 736 | [ 737 | "arn:", 738 | { 739 | "Ref": "AWS::Partition" 740 | }, 741 | ":execute-api:", 742 | { 743 | "Ref": "AWS::Region" 744 | }, 745 | ":", 746 | { 747 | "Ref": "AWS::AccountId" 748 | }, 749 | ":", 750 | { 751 | "Ref": "ApiGatewayRestApi" 752 | }, 753 | "/*/*" 754 | ] 755 | ] 756 | } 757 | } 758 | }, 759 | "GetTodoLambdaPermissionApiGateway": { 760 | "Type": "AWS::Lambda::Permission", 761 | "Properties": { 762 | "FunctionName": { 763 | "Fn::GetAtt": [ 764 | "GetTodoLambdaFunction", 765 | "Arn" 766 | ] 767 | }, 768 | "Action": "lambda:InvokeFunction", 769 | "Principal": "apigateway.amazonaws.com", 770 | "SourceArn": { 771 | "Fn::Join": [ 772 | "", 773 | [ 774 | "arn:", 775 | { 776 | "Ref": "AWS::Partition" 777 | }, 778 | ":execute-api:", 779 | { 780 | "Ref": "AWS::Region" 781 | }, 782 | ":", 783 | { 784 | "Ref": "AWS::AccountId" 785 | }, 786 | ":", 787 | { 788 | "Ref": "ApiGatewayRestApi" 789 | }, 790 | "/*/*" 791 | ] 792 | ] 793 | } 794 | } 795 | }, 796 | "UpdateTodoLambdaPermissionApiGateway": { 797 | "Type": "AWS::Lambda::Permission", 798 | "Properties": { 799 | "FunctionName": { 800 | "Fn::GetAtt": [ 801 | "UpdateTodoLambdaFunction", 802 | "Arn" 803 | ] 804 | }, 805 | "Action": "lambda:InvokeFunction", 806 | "Principal": "apigateway.amazonaws.com", 807 | "SourceArn": { 808 | "Fn::Join": [ 809 | "", 810 | [ 811 | "arn:", 812 | { 813 | "Ref": "AWS::Partition" 814 | }, 815 | ":execute-api:", 816 | { 817 | "Ref": "AWS::Region" 818 | }, 819 | ":", 820 | { 821 | "Ref": "AWS::AccountId" 822 | }, 823 | ":", 824 | { 825 | "Ref": "ApiGatewayRestApi" 826 | }, 827 | "/*/*" 828 | ] 829 | ] 830 | } 831 | } 832 | }, 833 | "DeleteTodoLambdaPermissionApiGateway": { 834 | "Type": "AWS::Lambda::Permission", 835 | "Properties": { 836 | "FunctionName": { 837 | "Fn::GetAtt": [ 838 | "DeleteTodoLambdaFunction", 839 | "Arn" 840 | ] 841 | }, 842 | "Action": "lambda:InvokeFunction", 843 | "Principal": "apigateway.amazonaws.com", 844 | "SourceArn": { 845 | "Fn::Join": [ 846 | "", 847 | [ 848 | "arn:", 849 | { 850 | "Ref": "AWS::Partition" 851 | }, 852 | ":execute-api:", 853 | { 854 | "Ref": "AWS::Region" 855 | }, 856 | ":", 857 | { 858 | "Ref": "AWS::AccountId" 859 | }, 860 | ":", 861 | { 862 | "Ref": "ApiGatewayRestApi" 863 | }, 864 | "/*/*" 865 | ] 866 | ] 867 | } 868 | } 869 | }, 870 | "TodosTable": { 871 | "Type": "AWS::DynamoDB::Table", 872 | "Properties": { 873 | "TableName": "TodosTable2", 874 | "AttributeDefinitions": [ 875 | { 876 | "AttributeName": "todosId", 877 | "AttributeType": "S" 878 | } 879 | ], 880 | "KeySchema": [ 881 | { 882 | "AttributeName": "todosId", 883 | "KeyType": "HASH" 884 | } 885 | ], 886 | "ProvisionedThroughput": { 887 | "ReadCapacityUnits": 1, 888 | "WriteCapacityUnits": 1 889 | } 890 | } 891 | } 892 | }, 893 | "Outputs": { 894 | "ServerlessDeploymentBucketName": { 895 | "Value": { 896 | "Ref": "ServerlessDeploymentBucket" 897 | }, 898 | "Export": { 899 | "Name": "sls-aws-serverless-typescript-api-dev-ServerlessDeploymentBucketName" 900 | } 901 | }, 902 | "GetAllTodosLambdaFunctionQualifiedArn": { 903 | "Description": "Current Lambda function version", 904 | "Value": { 905 | "Ref": "GetAllTodosLambdaVersionp0CdOAiYHjhgPjyDDwjPIiT67HNeYsAeWdmrnmD0" 906 | }, 907 | "Export": { 908 | "Name": "sls-aws-serverless-typescript-api-dev-GetAllTodosLambdaFunctionQualifiedArn" 909 | } 910 | }, 911 | "CreateTodoLambdaFunctionQualifiedArn": { 912 | "Description": "Current Lambda function version", 913 | "Value": { 914 | "Ref": "CreateTodoLambdaVersionXASP5192wCR21kDeCZSW2spvZzTajrBSkq3BwEdYhU" 915 | }, 916 | "Export": { 917 | "Name": "sls-aws-serverless-typescript-api-dev-CreateTodoLambdaFunctionQualifiedArn" 918 | } 919 | }, 920 | "GetTodoLambdaFunctionQualifiedArn": { 921 | "Description": "Current Lambda function version", 922 | "Value": { 923 | "Ref": "GetTodoLambdaVersionE8UrAWLkP0Xh97xb7Pk6lktuR6dCIdZy7MEiRC18zA" 924 | }, 925 | "Export": { 926 | "Name": "sls-aws-serverless-typescript-api-dev-GetTodoLambdaFunctionQualifiedArn" 927 | } 928 | }, 929 | "UpdateTodoLambdaFunctionQualifiedArn": { 930 | "Description": "Current Lambda function version", 931 | "Value": { 932 | "Ref": "UpdateTodoLambdaVersionVDAD1c1Pj3YQdlUHsBhnKhoPlfMmuYkH5Agsqso" 933 | }, 934 | "Export": { 935 | "Name": "sls-aws-serverless-typescript-api-dev-UpdateTodoLambdaFunctionQualifiedArn" 936 | } 937 | }, 938 | "DeleteTodoLambdaFunctionQualifiedArn": { 939 | "Description": "Current Lambda function version", 940 | "Value": { 941 | "Ref": "DeleteTodoLambdaVersionlgAsU51djBs58IU60SiryGSQF1gcQovPswjRv2Hvi4" 942 | }, 943 | "Export": { 944 | "Name": "sls-aws-serverless-typescript-api-dev-DeleteTodoLambdaFunctionQualifiedArn" 945 | } 946 | }, 947 | "ServiceEndpoint": { 948 | "Description": "URL of the service endpoint", 949 | "Value": { 950 | "Fn::Join": [ 951 | "", 952 | [ 953 | "https://", 954 | { 955 | "Ref": "ApiGatewayRestApi" 956 | }, 957 | ".execute-api.", 958 | { 959 | "Ref": "AWS::Region" 960 | }, 961 | ".", 962 | { 963 | "Ref": "AWS::URLSuffix" 964 | }, 965 | "/dev" 966 | ] 967 | ] 968 | }, 969 | "Export": { 970 | "Name": "sls-aws-serverless-typescript-api-dev-ServiceEndpoint" 971 | } 972 | } 973 | } 974 | } -------------------------------------------------------------------------------- /.serverless/serverless-state.json: -------------------------------------------------------------------------------- 1 | { 2 | "service": { 3 | "service": "aws-serverless-typescript-api", 4 | "serviceObject": { 5 | "name": "aws-serverless-typescript-api" 6 | }, 7 | "provider": { 8 | "name": "aws", 9 | "runtime": "nodejs14.x", 10 | "apiGateway": { 11 | "minimumCompressionSize": 1024, 12 | "shouldStartNameWithService": true 13 | }, 14 | "environment": { 15 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 16 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 17 | }, 18 | "iam": { 19 | "role": { 20 | "statements": [ 21 | { 22 | "Effect": "Allow", 23 | "Action": [ 24 | "dynamodb:DescribeTable", 25 | "dynamodb:Query", 26 | "dynamodb:Scan", 27 | "dynamodb:GetItem", 28 | "dynamodb:PutItem", 29 | "dynamodb:UpdateItem", 30 | "dynamodb:DeleteItem" 31 | ], 32 | "Resource": "arn:aws:dynamodb:us-west-2:*:table/TodosTable2" 33 | } 34 | ] 35 | } 36 | }, 37 | "stage": "dev", 38 | "region": "us-east-1", 39 | "versionFunctions": true, 40 | "compiledCloudFormationTemplate": { 41 | "AWSTemplateFormatVersion": "2010-09-09", 42 | "Description": "The AWS CloudFormation template for this Serverless application", 43 | "Resources": { 44 | "ServerlessDeploymentBucket": { 45 | "Type": "AWS::S3::Bucket", 46 | "Properties": { 47 | "BucketEncryption": { 48 | "ServerSideEncryptionConfiguration": [ 49 | { 50 | "ServerSideEncryptionByDefault": { 51 | "SSEAlgorithm": "AES256" 52 | } 53 | } 54 | ] 55 | } 56 | } 57 | }, 58 | "ServerlessDeploymentBucketPolicy": { 59 | "Type": "AWS::S3::BucketPolicy", 60 | "Properties": { 61 | "Bucket": { 62 | "Ref": "ServerlessDeploymentBucket" 63 | }, 64 | "PolicyDocument": { 65 | "Statement": [ 66 | { 67 | "Action": "s3:*", 68 | "Effect": "Deny", 69 | "Principal": "*", 70 | "Resource": [ 71 | { 72 | "Fn::Join": [ 73 | "", 74 | [ 75 | "arn:", 76 | { 77 | "Ref": "AWS::Partition" 78 | }, 79 | ":s3:::", 80 | { 81 | "Ref": "ServerlessDeploymentBucket" 82 | }, 83 | "/*" 84 | ] 85 | ] 86 | }, 87 | { 88 | "Fn::Join": [ 89 | "", 90 | [ 91 | "arn:", 92 | { 93 | "Ref": "AWS::Partition" 94 | }, 95 | ":s3:::", 96 | { 97 | "Ref": "ServerlessDeploymentBucket" 98 | } 99 | ] 100 | ] 101 | } 102 | ], 103 | "Condition": { 104 | "Bool": { 105 | "aws:SecureTransport": false 106 | } 107 | } 108 | } 109 | ] 110 | } 111 | } 112 | }, 113 | "GetAllTodosLogGroup": { 114 | "Type": "AWS::Logs::LogGroup", 115 | "Properties": { 116 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-getAllTodos" 117 | } 118 | }, 119 | "CreateTodoLogGroup": { 120 | "Type": "AWS::Logs::LogGroup", 121 | "Properties": { 122 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-createTodo" 123 | } 124 | }, 125 | "GetTodoLogGroup": { 126 | "Type": "AWS::Logs::LogGroup", 127 | "Properties": { 128 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-getTodo" 129 | } 130 | }, 131 | "UpdateTodoLogGroup": { 132 | "Type": "AWS::Logs::LogGroup", 133 | "Properties": { 134 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-updateTodo" 135 | } 136 | }, 137 | "DeleteTodoLogGroup": { 138 | "Type": "AWS::Logs::LogGroup", 139 | "Properties": { 140 | "LogGroupName": "/aws/lambda/aws-serverless-typescript-api-dev-deleteTodo" 141 | } 142 | }, 143 | "IamRoleLambdaExecution": { 144 | "Type": "AWS::IAM::Role", 145 | "Properties": { 146 | "AssumeRolePolicyDocument": { 147 | "Version": "2012-10-17", 148 | "Statement": [ 149 | { 150 | "Effect": "Allow", 151 | "Principal": { 152 | "Service": [ 153 | "lambda.amazonaws.com" 154 | ] 155 | }, 156 | "Action": [ 157 | "sts:AssumeRole" 158 | ] 159 | } 160 | ] 161 | }, 162 | "Policies": [ 163 | { 164 | "PolicyName": { 165 | "Fn::Join": [ 166 | "-", 167 | [ 168 | "aws-serverless-typescript-api", 169 | "dev", 170 | "lambda" 171 | ] 172 | ] 173 | }, 174 | "PolicyDocument": { 175 | "Version": "2012-10-17", 176 | "Statement": [ 177 | { 178 | "Effect": "Allow", 179 | "Action": [ 180 | "logs:CreateLogStream", 181 | "logs:CreateLogGroup" 182 | ], 183 | "Resource": [ 184 | { 185 | "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-serverless-typescript-api-dev*:*" 186 | } 187 | ] 188 | }, 189 | { 190 | "Effect": "Allow", 191 | "Action": [ 192 | "logs:PutLogEvents" 193 | ], 194 | "Resource": [ 195 | { 196 | "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-serverless-typescript-api-dev*:*:*" 197 | } 198 | ] 199 | }, 200 | { 201 | "$ref": "$[\"service\"][\"provider\"][\"iam\"][\"role\"][\"statements\"][0]" 202 | } 203 | ] 204 | } 205 | } 206 | ], 207 | "Path": "/", 208 | "RoleName": { 209 | "Fn::Join": [ 210 | "-", 211 | [ 212 | "aws-serverless-typescript-api", 213 | "dev", 214 | { 215 | "Ref": "AWS::Region" 216 | }, 217 | "lambdaRole" 218 | ] 219 | ] 220 | } 221 | } 222 | }, 223 | "GetAllTodosLambdaFunction": { 224 | "Type": "AWS::Lambda::Function", 225 | "Properties": { 226 | "Code": { 227 | "S3Bucket": { 228 | "Ref": "ServerlessDeploymentBucket" 229 | }, 230 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/getAllTodos.zip" 231 | }, 232 | "Handler": "src/functions/todo/handler.getAllTodos", 233 | "Runtime": "nodejs14.x", 234 | "FunctionName": "aws-serverless-typescript-api-dev-getAllTodos", 235 | "MemorySize": 1024, 236 | "Timeout": 6, 237 | "Environment": { 238 | "Variables": { 239 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 240 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 241 | } 242 | }, 243 | "Role": { 244 | "Fn::GetAtt": [ 245 | "IamRoleLambdaExecution", 246 | "Arn" 247 | ] 248 | } 249 | }, 250 | "DependsOn": [ 251 | "GetAllTodosLogGroup" 252 | ] 253 | }, 254 | "CreateTodoLambdaFunction": { 255 | "Type": "AWS::Lambda::Function", 256 | "Properties": { 257 | "Code": { 258 | "S3Bucket": { 259 | "Ref": "ServerlessDeploymentBucket" 260 | }, 261 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/createTodo.zip" 262 | }, 263 | "Handler": "src/functions/todo/handler.createTodo", 264 | "Runtime": "nodejs14.x", 265 | "FunctionName": "aws-serverless-typescript-api-dev-createTodo", 266 | "MemorySize": 1024, 267 | "Timeout": 6, 268 | "Environment": { 269 | "Variables": { 270 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 271 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 272 | } 273 | }, 274 | "Role": { 275 | "Fn::GetAtt": [ 276 | "IamRoleLambdaExecution", 277 | "Arn" 278 | ] 279 | } 280 | }, 281 | "DependsOn": [ 282 | "CreateTodoLogGroup" 283 | ] 284 | }, 285 | "GetTodoLambdaFunction": { 286 | "Type": "AWS::Lambda::Function", 287 | "Properties": { 288 | "Code": { 289 | "S3Bucket": { 290 | "Ref": "ServerlessDeploymentBucket" 291 | }, 292 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/getTodo.zip" 293 | }, 294 | "Handler": "src/functions/todo/handler.getTodo", 295 | "Runtime": "nodejs14.x", 296 | "FunctionName": "aws-serverless-typescript-api-dev-getTodo", 297 | "MemorySize": 1024, 298 | "Timeout": 6, 299 | "Environment": { 300 | "Variables": { 301 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 302 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 303 | } 304 | }, 305 | "Role": { 306 | "Fn::GetAtt": [ 307 | "IamRoleLambdaExecution", 308 | "Arn" 309 | ] 310 | } 311 | }, 312 | "DependsOn": [ 313 | "GetTodoLogGroup" 314 | ] 315 | }, 316 | "UpdateTodoLambdaFunction": { 317 | "Type": "AWS::Lambda::Function", 318 | "Properties": { 319 | "Code": { 320 | "S3Bucket": { 321 | "Ref": "ServerlessDeploymentBucket" 322 | }, 323 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/updateTodo.zip" 324 | }, 325 | "Handler": "src/functions/todo/handler.updateTodo", 326 | "Runtime": "nodejs14.x", 327 | "FunctionName": "aws-serverless-typescript-api-dev-updateTodo", 328 | "MemorySize": 1024, 329 | "Timeout": 6, 330 | "Environment": { 331 | "Variables": { 332 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 333 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 334 | } 335 | }, 336 | "Role": { 337 | "Fn::GetAtt": [ 338 | "IamRoleLambdaExecution", 339 | "Arn" 340 | ] 341 | } 342 | }, 343 | "DependsOn": [ 344 | "UpdateTodoLogGroup" 345 | ] 346 | }, 347 | "DeleteTodoLambdaFunction": { 348 | "Type": "AWS::Lambda::Function", 349 | "Properties": { 350 | "Code": { 351 | "S3Bucket": { 352 | "Ref": "ServerlessDeploymentBucket" 353 | }, 354 | "S3Key": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z/deleteTodo.zip" 355 | }, 356 | "Handler": "src/functions/todo/handler.deleteTodo", 357 | "Runtime": "nodejs14.x", 358 | "FunctionName": "aws-serverless-typescript-api-dev-deleteTodo", 359 | "MemorySize": 1024, 360 | "Timeout": 6, 361 | "Environment": { 362 | "Variables": { 363 | "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1", 364 | "NODE_OPTIONS": "--enable-source-maps --stack-trace-limit=1000" 365 | } 366 | }, 367 | "Role": { 368 | "Fn::GetAtt": [ 369 | "IamRoleLambdaExecution", 370 | "Arn" 371 | ] 372 | } 373 | }, 374 | "DependsOn": [ 375 | "DeleteTodoLogGroup" 376 | ] 377 | }, 378 | "GetAllTodosLambdaVersionp0CdOAiYHjhgPjyDDwjPIiT67HNeYsAeWdmrnmD0": { 379 | "Type": "AWS::Lambda::Version", 380 | "DeletionPolicy": "Retain", 381 | "Properties": { 382 | "FunctionName": { 383 | "Ref": "GetAllTodosLambdaFunction" 384 | }, 385 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 386 | } 387 | }, 388 | "CreateTodoLambdaVersionXASP5192wCR21kDeCZSW2spvZzTajrBSkq3BwEdYhU": { 389 | "Type": "AWS::Lambda::Version", 390 | "DeletionPolicy": "Retain", 391 | "Properties": { 392 | "FunctionName": { 393 | "Ref": "CreateTodoLambdaFunction" 394 | }, 395 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 396 | } 397 | }, 398 | "GetTodoLambdaVersionE8UrAWLkP0Xh97xb7Pk6lktuR6dCIdZy7MEiRC18zA": { 399 | "Type": "AWS::Lambda::Version", 400 | "DeletionPolicy": "Retain", 401 | "Properties": { 402 | "FunctionName": { 403 | "Ref": "GetTodoLambdaFunction" 404 | }, 405 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 406 | } 407 | }, 408 | "UpdateTodoLambdaVersionVDAD1c1Pj3YQdlUHsBhnKhoPlfMmuYkH5Agsqso": { 409 | "Type": "AWS::Lambda::Version", 410 | "DeletionPolicy": "Retain", 411 | "Properties": { 412 | "FunctionName": { 413 | "Ref": "UpdateTodoLambdaFunction" 414 | }, 415 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 416 | } 417 | }, 418 | "DeleteTodoLambdaVersionlgAsU51djBs58IU60SiryGSQF1gcQovPswjRv2Hvi4": { 419 | "Type": "AWS::Lambda::Version", 420 | "DeletionPolicy": "Retain", 421 | "Properties": { 422 | "FunctionName": { 423 | "Ref": "DeleteTodoLambdaFunction" 424 | }, 425 | "CodeSha256": "AHKLBlAdG9V4RT0g6vJy38/FOlBGpk331Fc0OpgflVU=" 426 | } 427 | }, 428 | "ApiGatewayRestApi": { 429 | "Type": "AWS::ApiGateway::RestApi", 430 | "Properties": { 431 | "Name": "aws-serverless-typescript-api-dev", 432 | "EndpointConfiguration": { 433 | "Types": [ 434 | "EDGE" 435 | ] 436 | }, 437 | "Policy": "", 438 | "MinimumCompressionSize": 1024 439 | } 440 | }, 441 | "ApiGatewayResourceTodo": { 442 | "Type": "AWS::ApiGateway::Resource", 443 | "Properties": { 444 | "ParentId": { 445 | "Fn::GetAtt": [ 446 | "ApiGatewayRestApi", 447 | "RootResourceId" 448 | ] 449 | }, 450 | "PathPart": "todo", 451 | "RestApiId": { 452 | "Ref": "ApiGatewayRestApi" 453 | } 454 | } 455 | }, 456 | "ApiGatewayResourceTodoIdVar": { 457 | "Type": "AWS::ApiGateway::Resource", 458 | "Properties": { 459 | "ParentId": { 460 | "Ref": "ApiGatewayResourceTodo" 461 | }, 462 | "PathPart": "{id}", 463 | "RestApiId": { 464 | "Ref": "ApiGatewayRestApi" 465 | } 466 | } 467 | }, 468 | "ApiGatewayMethodTodoGet": { 469 | "Type": "AWS::ApiGateway::Method", 470 | "Properties": { 471 | "HttpMethod": "GET", 472 | "RequestParameters": {}, 473 | "ResourceId": { 474 | "Ref": "ApiGatewayResourceTodo" 475 | }, 476 | "RestApiId": { 477 | "Ref": "ApiGatewayRestApi" 478 | }, 479 | "ApiKeyRequired": false, 480 | "AuthorizationType": "NONE", 481 | "Integration": { 482 | "IntegrationHttpMethod": "POST", 483 | "Type": "AWS_PROXY", 484 | "Uri": { 485 | "Fn::Join": [ 486 | "", 487 | [ 488 | "arn:", 489 | { 490 | "Ref": "AWS::Partition" 491 | }, 492 | ":apigateway:", 493 | { 494 | "Ref": "AWS::Region" 495 | }, 496 | ":lambda:path/2015-03-31/functions/", 497 | { 498 | "Fn::GetAtt": [ 499 | "GetAllTodosLambdaFunction", 500 | "Arn" 501 | ] 502 | }, 503 | "/invocations" 504 | ] 505 | ] 506 | } 507 | }, 508 | "MethodResponses": [] 509 | }, 510 | "DependsOn": [ 511 | "GetAllTodosLambdaPermissionApiGateway" 512 | ] 513 | }, 514 | "ApiGatewayMethodTodoPost": { 515 | "Type": "AWS::ApiGateway::Method", 516 | "Properties": { 517 | "HttpMethod": "POST", 518 | "RequestParameters": {}, 519 | "ResourceId": { 520 | "Ref": "ApiGatewayResourceTodo" 521 | }, 522 | "RestApiId": { 523 | "Ref": "ApiGatewayRestApi" 524 | }, 525 | "ApiKeyRequired": false, 526 | "AuthorizationType": "NONE", 527 | "Integration": { 528 | "IntegrationHttpMethod": "POST", 529 | "Type": "AWS_PROXY", 530 | "Uri": { 531 | "Fn::Join": [ 532 | "", 533 | [ 534 | "arn:", 535 | { 536 | "Ref": "AWS::Partition" 537 | }, 538 | ":apigateway:", 539 | { 540 | "Ref": "AWS::Region" 541 | }, 542 | ":lambda:path/2015-03-31/functions/", 543 | { 544 | "Fn::GetAtt": [ 545 | "CreateTodoLambdaFunction", 546 | "Arn" 547 | ] 548 | }, 549 | "/invocations" 550 | ] 551 | ] 552 | } 553 | }, 554 | "MethodResponses": [] 555 | }, 556 | "DependsOn": [ 557 | "CreateTodoLambdaPermissionApiGateway" 558 | ] 559 | }, 560 | "ApiGatewayMethodTodoIdVarGet": { 561 | "Type": "AWS::ApiGateway::Method", 562 | "Properties": { 563 | "HttpMethod": "GET", 564 | "RequestParameters": {}, 565 | "ResourceId": { 566 | "Ref": "ApiGatewayResourceTodoIdVar" 567 | }, 568 | "RestApiId": { 569 | "Ref": "ApiGatewayRestApi" 570 | }, 571 | "ApiKeyRequired": false, 572 | "AuthorizationType": "NONE", 573 | "Integration": { 574 | "IntegrationHttpMethod": "POST", 575 | "Type": "AWS_PROXY", 576 | "Uri": { 577 | "Fn::Join": [ 578 | "", 579 | [ 580 | "arn:", 581 | { 582 | "Ref": "AWS::Partition" 583 | }, 584 | ":apigateway:", 585 | { 586 | "Ref": "AWS::Region" 587 | }, 588 | ":lambda:path/2015-03-31/functions/", 589 | { 590 | "Fn::GetAtt": [ 591 | "GetTodoLambdaFunction", 592 | "Arn" 593 | ] 594 | }, 595 | "/invocations" 596 | ] 597 | ] 598 | } 599 | }, 600 | "MethodResponses": [] 601 | }, 602 | "DependsOn": [ 603 | "GetTodoLambdaPermissionApiGateway" 604 | ] 605 | }, 606 | "ApiGatewayMethodTodoIdVarPut": { 607 | "Type": "AWS::ApiGateway::Method", 608 | "Properties": { 609 | "HttpMethod": "PUT", 610 | "RequestParameters": {}, 611 | "ResourceId": { 612 | "Ref": "ApiGatewayResourceTodoIdVar" 613 | }, 614 | "RestApiId": { 615 | "Ref": "ApiGatewayRestApi" 616 | }, 617 | "ApiKeyRequired": false, 618 | "AuthorizationType": "NONE", 619 | "Integration": { 620 | "IntegrationHttpMethod": "POST", 621 | "Type": "AWS_PROXY", 622 | "Uri": { 623 | "Fn::Join": [ 624 | "", 625 | [ 626 | "arn:", 627 | { 628 | "Ref": "AWS::Partition" 629 | }, 630 | ":apigateway:", 631 | { 632 | "Ref": "AWS::Region" 633 | }, 634 | ":lambda:path/2015-03-31/functions/", 635 | { 636 | "Fn::GetAtt": [ 637 | "UpdateTodoLambdaFunction", 638 | "Arn" 639 | ] 640 | }, 641 | "/invocations" 642 | ] 643 | ] 644 | } 645 | }, 646 | "MethodResponses": [] 647 | }, 648 | "DependsOn": [ 649 | "UpdateTodoLambdaPermissionApiGateway" 650 | ] 651 | }, 652 | "ApiGatewayMethodTodoIdVarDelete": { 653 | "Type": "AWS::ApiGateway::Method", 654 | "Properties": { 655 | "HttpMethod": "DELETE", 656 | "RequestParameters": {}, 657 | "ResourceId": { 658 | "Ref": "ApiGatewayResourceTodoIdVar" 659 | }, 660 | "RestApiId": { 661 | "Ref": "ApiGatewayRestApi" 662 | }, 663 | "ApiKeyRequired": false, 664 | "AuthorizationType": "NONE", 665 | "Integration": { 666 | "IntegrationHttpMethod": "POST", 667 | "Type": "AWS_PROXY", 668 | "Uri": { 669 | "Fn::Join": [ 670 | "", 671 | [ 672 | "arn:", 673 | { 674 | "Ref": "AWS::Partition" 675 | }, 676 | ":apigateway:", 677 | { 678 | "Ref": "AWS::Region" 679 | }, 680 | ":lambda:path/2015-03-31/functions/", 681 | { 682 | "Fn::GetAtt": [ 683 | "DeleteTodoLambdaFunction", 684 | "Arn" 685 | ] 686 | }, 687 | "/invocations" 688 | ] 689 | ] 690 | } 691 | }, 692 | "MethodResponses": [] 693 | }, 694 | "DependsOn": [ 695 | "DeleteTodoLambdaPermissionApiGateway" 696 | ] 697 | }, 698 | "ApiGatewayDeployment1643643477891": { 699 | "Type": "AWS::ApiGateway::Deployment", 700 | "Properties": { 701 | "RestApiId": { 702 | "Ref": "ApiGatewayRestApi" 703 | }, 704 | "StageName": "dev" 705 | }, 706 | "DependsOn": [ 707 | "ApiGatewayMethodTodoGet", 708 | "ApiGatewayMethodTodoPost", 709 | "ApiGatewayMethodTodoIdVarGet", 710 | "ApiGatewayMethodTodoIdVarPut", 711 | "ApiGatewayMethodTodoIdVarDelete" 712 | ] 713 | }, 714 | "GetAllTodosLambdaPermissionApiGateway": { 715 | "Type": "AWS::Lambda::Permission", 716 | "Properties": { 717 | "FunctionName": { 718 | "Fn::GetAtt": [ 719 | "GetAllTodosLambdaFunction", 720 | "Arn" 721 | ] 722 | }, 723 | "Action": "lambda:InvokeFunction", 724 | "Principal": "apigateway.amazonaws.com", 725 | "SourceArn": { 726 | "Fn::Join": [ 727 | "", 728 | [ 729 | "arn:", 730 | { 731 | "Ref": "AWS::Partition" 732 | }, 733 | ":execute-api:", 734 | { 735 | "Ref": "AWS::Region" 736 | }, 737 | ":", 738 | { 739 | "Ref": "AWS::AccountId" 740 | }, 741 | ":", 742 | { 743 | "Ref": "ApiGatewayRestApi" 744 | }, 745 | "/*/*" 746 | ] 747 | ] 748 | } 749 | } 750 | }, 751 | "CreateTodoLambdaPermissionApiGateway": { 752 | "Type": "AWS::Lambda::Permission", 753 | "Properties": { 754 | "FunctionName": { 755 | "Fn::GetAtt": [ 756 | "CreateTodoLambdaFunction", 757 | "Arn" 758 | ] 759 | }, 760 | "Action": "lambda:InvokeFunction", 761 | "Principal": "apigateway.amazonaws.com", 762 | "SourceArn": { 763 | "Fn::Join": [ 764 | "", 765 | [ 766 | "arn:", 767 | { 768 | "Ref": "AWS::Partition" 769 | }, 770 | ":execute-api:", 771 | { 772 | "Ref": "AWS::Region" 773 | }, 774 | ":", 775 | { 776 | "Ref": "AWS::AccountId" 777 | }, 778 | ":", 779 | { 780 | "Ref": "ApiGatewayRestApi" 781 | }, 782 | "/*/*" 783 | ] 784 | ] 785 | } 786 | } 787 | }, 788 | "GetTodoLambdaPermissionApiGateway": { 789 | "Type": "AWS::Lambda::Permission", 790 | "Properties": { 791 | "FunctionName": { 792 | "Fn::GetAtt": [ 793 | "GetTodoLambdaFunction", 794 | "Arn" 795 | ] 796 | }, 797 | "Action": "lambda:InvokeFunction", 798 | "Principal": "apigateway.amazonaws.com", 799 | "SourceArn": { 800 | "Fn::Join": [ 801 | "", 802 | [ 803 | "arn:", 804 | { 805 | "Ref": "AWS::Partition" 806 | }, 807 | ":execute-api:", 808 | { 809 | "Ref": "AWS::Region" 810 | }, 811 | ":", 812 | { 813 | "Ref": "AWS::AccountId" 814 | }, 815 | ":", 816 | { 817 | "Ref": "ApiGatewayRestApi" 818 | }, 819 | "/*/*" 820 | ] 821 | ] 822 | } 823 | } 824 | }, 825 | "UpdateTodoLambdaPermissionApiGateway": { 826 | "Type": "AWS::Lambda::Permission", 827 | "Properties": { 828 | "FunctionName": { 829 | "Fn::GetAtt": [ 830 | "UpdateTodoLambdaFunction", 831 | "Arn" 832 | ] 833 | }, 834 | "Action": "lambda:InvokeFunction", 835 | "Principal": "apigateway.amazonaws.com", 836 | "SourceArn": { 837 | "Fn::Join": [ 838 | "", 839 | [ 840 | "arn:", 841 | { 842 | "Ref": "AWS::Partition" 843 | }, 844 | ":execute-api:", 845 | { 846 | "Ref": "AWS::Region" 847 | }, 848 | ":", 849 | { 850 | "Ref": "AWS::AccountId" 851 | }, 852 | ":", 853 | { 854 | "Ref": "ApiGatewayRestApi" 855 | }, 856 | "/*/*" 857 | ] 858 | ] 859 | } 860 | } 861 | }, 862 | "DeleteTodoLambdaPermissionApiGateway": { 863 | "Type": "AWS::Lambda::Permission", 864 | "Properties": { 865 | "FunctionName": { 866 | "Fn::GetAtt": [ 867 | "DeleteTodoLambdaFunction", 868 | "Arn" 869 | ] 870 | }, 871 | "Action": "lambda:InvokeFunction", 872 | "Principal": "apigateway.amazonaws.com", 873 | "SourceArn": { 874 | "Fn::Join": [ 875 | "", 876 | [ 877 | "arn:", 878 | { 879 | "Ref": "AWS::Partition" 880 | }, 881 | ":execute-api:", 882 | { 883 | "Ref": "AWS::Region" 884 | }, 885 | ":", 886 | { 887 | "Ref": "AWS::AccountId" 888 | }, 889 | ":", 890 | { 891 | "Ref": "ApiGatewayRestApi" 892 | }, 893 | "/*/*" 894 | ] 895 | ] 896 | } 897 | } 898 | }, 899 | "TodosTable": { 900 | "Type": "AWS::DynamoDB::Table", 901 | "Properties": { 902 | "TableName": "TodosTable2", 903 | "AttributeDefinitions": [ 904 | { 905 | "AttributeName": "todosId", 906 | "AttributeType": "S" 907 | } 908 | ], 909 | "KeySchema": [ 910 | { 911 | "AttributeName": "todosId", 912 | "KeyType": "HASH" 913 | } 914 | ], 915 | "ProvisionedThroughput": { 916 | "ReadCapacityUnits": 1, 917 | "WriteCapacityUnits": 1 918 | } 919 | } 920 | } 921 | }, 922 | "Outputs": { 923 | "ServerlessDeploymentBucketName": { 924 | "Value": { 925 | "Ref": "ServerlessDeploymentBucket" 926 | }, 927 | "Export": { 928 | "Name": "sls-aws-serverless-typescript-api-dev-ServerlessDeploymentBucketName" 929 | } 930 | }, 931 | "GetAllTodosLambdaFunctionQualifiedArn": { 932 | "Description": "Current Lambda function version", 933 | "Value": { 934 | "Ref": "GetAllTodosLambdaVersionp0CdOAiYHjhgPjyDDwjPIiT67HNeYsAeWdmrnmD0" 935 | }, 936 | "Export": { 937 | "Name": "sls-aws-serverless-typescript-api-dev-GetAllTodosLambdaFunctionQualifiedArn" 938 | } 939 | }, 940 | "CreateTodoLambdaFunctionQualifiedArn": { 941 | "Description": "Current Lambda function version", 942 | "Value": { 943 | "Ref": "CreateTodoLambdaVersionXASP5192wCR21kDeCZSW2spvZzTajrBSkq3BwEdYhU" 944 | }, 945 | "Export": { 946 | "Name": "sls-aws-serverless-typescript-api-dev-CreateTodoLambdaFunctionQualifiedArn" 947 | } 948 | }, 949 | "GetTodoLambdaFunctionQualifiedArn": { 950 | "Description": "Current Lambda function version", 951 | "Value": { 952 | "Ref": "GetTodoLambdaVersionE8UrAWLkP0Xh97xb7Pk6lktuR6dCIdZy7MEiRC18zA" 953 | }, 954 | "Export": { 955 | "Name": "sls-aws-serverless-typescript-api-dev-GetTodoLambdaFunctionQualifiedArn" 956 | } 957 | }, 958 | "UpdateTodoLambdaFunctionQualifiedArn": { 959 | "Description": "Current Lambda function version", 960 | "Value": { 961 | "Ref": "UpdateTodoLambdaVersionVDAD1c1Pj3YQdlUHsBhnKhoPlfMmuYkH5Agsqso" 962 | }, 963 | "Export": { 964 | "Name": "sls-aws-serverless-typescript-api-dev-UpdateTodoLambdaFunctionQualifiedArn" 965 | } 966 | }, 967 | "DeleteTodoLambdaFunctionQualifiedArn": { 968 | "Description": "Current Lambda function version", 969 | "Value": { 970 | "Ref": "DeleteTodoLambdaVersionlgAsU51djBs58IU60SiryGSQF1gcQovPswjRv2Hvi4" 971 | }, 972 | "Export": { 973 | "Name": "sls-aws-serverless-typescript-api-dev-DeleteTodoLambdaFunctionQualifiedArn" 974 | } 975 | }, 976 | "ServiceEndpoint": { 977 | "Description": "URL of the service endpoint", 978 | "Value": { 979 | "Fn::Join": [ 980 | "", 981 | [ 982 | "https://", 983 | { 984 | "Ref": "ApiGatewayRestApi" 985 | }, 986 | ".execute-api.", 987 | { 988 | "Ref": "AWS::Region" 989 | }, 990 | ".", 991 | { 992 | "Ref": "AWS::URLSuffix" 993 | }, 994 | "/dev" 995 | ] 996 | ] 997 | }, 998 | "Export": { 999 | "Name": "sls-aws-serverless-typescript-api-dev-ServiceEndpoint" 1000 | } 1001 | } 1002 | } 1003 | }, 1004 | "coreCloudFormationTemplate": { 1005 | "AWSTemplateFormatVersion": "2010-09-09", 1006 | "Description": "The AWS CloudFormation template for this Serverless application", 1007 | "Resources": { 1008 | "ServerlessDeploymentBucket": { 1009 | "Type": "AWS::S3::Bucket", 1010 | "Properties": { 1011 | "BucketEncryption": { 1012 | "ServerSideEncryptionConfiguration": [ 1013 | { 1014 | "ServerSideEncryptionByDefault": { 1015 | "SSEAlgorithm": "AES256" 1016 | } 1017 | } 1018 | ] 1019 | } 1020 | } 1021 | }, 1022 | "ServerlessDeploymentBucketPolicy": { 1023 | "Type": "AWS::S3::BucketPolicy", 1024 | "Properties": { 1025 | "Bucket": { 1026 | "Ref": "ServerlessDeploymentBucket" 1027 | }, 1028 | "PolicyDocument": { 1029 | "Statement": [ 1030 | { 1031 | "Action": "s3:*", 1032 | "Effect": "Deny", 1033 | "Principal": "*", 1034 | "Resource": [ 1035 | { 1036 | "Fn::Join": [ 1037 | "", 1038 | [ 1039 | "arn:", 1040 | { 1041 | "Ref": "AWS::Partition" 1042 | }, 1043 | ":s3:::", 1044 | { 1045 | "Ref": "ServerlessDeploymentBucket" 1046 | }, 1047 | "/*" 1048 | ] 1049 | ] 1050 | }, 1051 | { 1052 | "Fn::Join": [ 1053 | "", 1054 | [ 1055 | "arn:", 1056 | { 1057 | "Ref": "AWS::Partition" 1058 | }, 1059 | ":s3:::", 1060 | { 1061 | "Ref": "ServerlessDeploymentBucket" 1062 | } 1063 | ] 1064 | ] 1065 | } 1066 | ], 1067 | "Condition": { 1068 | "Bool": { 1069 | "aws:SecureTransport": false 1070 | } 1071 | } 1072 | } 1073 | ] 1074 | } 1075 | } 1076 | } 1077 | }, 1078 | "Outputs": { 1079 | "ServerlessDeploymentBucketName": { 1080 | "Value": { 1081 | "Ref": "ServerlessDeploymentBucket" 1082 | } 1083 | } 1084 | } 1085 | }, 1086 | "vpc": {} 1087 | }, 1088 | "custom": { 1089 | "esbuild": { 1090 | "bundle": true, 1091 | "minify": false, 1092 | "sourcemap": true, 1093 | "exclude": [ 1094 | "aws-sdk" 1095 | ], 1096 | "target": "node14", 1097 | "define": {}, 1098 | "platform": "node", 1099 | "concurrency": 10 1100 | }, 1101 | "dynamodb": { 1102 | "start": { 1103 | "port": 5000, 1104 | "inMemory": true, 1105 | "migrate": true 1106 | }, 1107 | "stages": "dev" 1108 | } 1109 | }, 1110 | "plugins": [ 1111 | "serverless-esbuild", 1112 | "serverless-offline", 1113 | "serverless-dynamodb-local" 1114 | ], 1115 | "pluginsData": {}, 1116 | "functions": { 1117 | "getAllTodos": { 1118 | "handler": "src/functions/todo/handler.getAllTodos", 1119 | "events": [ 1120 | { 1121 | "http": { 1122 | "method": "get", 1123 | "path": "todo", 1124 | "integration": "AWS_PROXY" 1125 | } 1126 | } 1127 | ], 1128 | "name": "aws-serverless-typescript-api-dev-getAllTodos", 1129 | "package": { 1130 | "artifact": "/home/programmer/ServerlessApps/aws-serverless-typescript-api/.serverless/getAllTodos.zip" 1131 | }, 1132 | "memory": 1024, 1133 | "timeout": 6, 1134 | "runtime": "nodejs14.x", 1135 | "vpc": {}, 1136 | "versionLogicalId": "GetAllTodosLambdaVersionp0CdOAiYHjhgPjyDDwjPIiT67HNeYsAeWdmrnmD0" 1137 | }, 1138 | "createTodo": { 1139 | "handler": "src/functions/todo/handler.createTodo", 1140 | "events": [ 1141 | { 1142 | "http": { 1143 | "method": "post", 1144 | "path": "todo", 1145 | "integration": "AWS_PROXY" 1146 | } 1147 | } 1148 | ], 1149 | "name": "aws-serverless-typescript-api-dev-createTodo", 1150 | "package": { 1151 | "artifact": "/home/programmer/ServerlessApps/aws-serverless-typescript-api/.serverless/createTodo.zip" 1152 | }, 1153 | "memory": 1024, 1154 | "timeout": 6, 1155 | "runtime": "nodejs14.x", 1156 | "vpc": {}, 1157 | "versionLogicalId": "CreateTodoLambdaVersionXASP5192wCR21kDeCZSW2spvZzTajrBSkq3BwEdYhU" 1158 | }, 1159 | "getTodo": { 1160 | "handler": "src/functions/todo/handler.getTodo", 1161 | "events": [ 1162 | { 1163 | "http": { 1164 | "method": "get", 1165 | "path": "todo/{id}", 1166 | "integration": "AWS_PROXY" 1167 | } 1168 | } 1169 | ], 1170 | "name": "aws-serverless-typescript-api-dev-getTodo", 1171 | "package": { 1172 | "artifact": "/home/programmer/ServerlessApps/aws-serverless-typescript-api/.serverless/getTodo.zip" 1173 | }, 1174 | "memory": 1024, 1175 | "timeout": 6, 1176 | "runtime": "nodejs14.x", 1177 | "vpc": {}, 1178 | "versionLogicalId": "GetTodoLambdaVersionE8UrAWLkP0Xh97xb7Pk6lktuR6dCIdZy7MEiRC18zA" 1179 | }, 1180 | "updateTodo": { 1181 | "handler": "src/functions/todo/handler.updateTodo", 1182 | "events": [ 1183 | { 1184 | "http": { 1185 | "method": "put", 1186 | "path": "todo/{id}", 1187 | "integration": "AWS_PROXY" 1188 | } 1189 | } 1190 | ], 1191 | "name": "aws-serverless-typescript-api-dev-updateTodo", 1192 | "package": { 1193 | "artifact": "/home/programmer/ServerlessApps/aws-serverless-typescript-api/.serverless/updateTodo.zip" 1194 | }, 1195 | "memory": 1024, 1196 | "timeout": 6, 1197 | "runtime": "nodejs14.x", 1198 | "vpc": {}, 1199 | "versionLogicalId": "UpdateTodoLambdaVersionVDAD1c1Pj3YQdlUHsBhnKhoPlfMmuYkH5Agsqso" 1200 | }, 1201 | "deleteTodo": { 1202 | "handler": "src/functions/todo/handler.deleteTodo", 1203 | "events": [ 1204 | { 1205 | "http": { 1206 | "method": "delete", 1207 | "path": "todo/{id}", 1208 | "integration": "AWS_PROXY" 1209 | } 1210 | } 1211 | ], 1212 | "name": "aws-serverless-typescript-api-dev-deleteTodo", 1213 | "package": { 1214 | "artifact": "/home/programmer/ServerlessApps/aws-serverless-typescript-api/.serverless/deleteTodo.zip" 1215 | }, 1216 | "memory": 1024, 1217 | "timeout": 6, 1218 | "runtime": "nodejs14.x", 1219 | "vpc": {}, 1220 | "versionLogicalId": "DeleteTodoLambdaVersionlgAsU51djBs58IU60SiryGSQF1gcQovPswjRv2Hvi4" 1221 | } 1222 | }, 1223 | "resources": { 1224 | "Resources": { 1225 | "TodosTable": { 1226 | "Type": "AWS::DynamoDB::Table", 1227 | "Properties": { 1228 | "TableName": "TodosTable2", 1229 | "AttributeDefinitions": [ 1230 | { 1231 | "AttributeName": "todosId", 1232 | "AttributeType": "S" 1233 | } 1234 | ], 1235 | "KeySchema": [ 1236 | { 1237 | "AttributeName": "todosId", 1238 | "KeyType": "HASH" 1239 | } 1240 | ], 1241 | "ProvisionedThroughput": { 1242 | "ReadCapacityUnits": 1, 1243 | "WriteCapacityUnits": 1 1244 | } 1245 | } 1246 | } 1247 | }, 1248 | "Outputs": {} 1249 | }, 1250 | "configValidationMode": "warn", 1251 | "serviceFilename": "serverless.ts", 1252 | "initialServerlessConfig": { 1253 | "service": "aws-serverless-typescript-api", 1254 | "frameworkVersion": "3", 1255 | "plugins": { 1256 | "$ref": "$[\"service\"][\"plugins\"]" 1257 | }, 1258 | "provider": { 1259 | "$ref": "$[\"service\"][\"provider\"]" 1260 | }, 1261 | "functions": { 1262 | "$ref": "$[\"service\"][\"functions\"]" 1263 | }, 1264 | "package": { 1265 | "individually": true 1266 | }, 1267 | "custom": { 1268 | "$ref": "$[\"service\"][\"custom\"]" 1269 | }, 1270 | "resources": { 1271 | "$ref": "$[\"service\"][\"resources\"]" 1272 | } 1273 | }, 1274 | "layers": {}, 1275 | "isDashboardMonitoringPreconfigured": false 1276 | }, 1277 | "package": { 1278 | "individually": true, 1279 | "artifactDirectoryName": "serverless/aws-serverless-typescript-api/dev/1643643481223-2022-01-31T15:38:01.223Z", 1280 | "artifact": "" 1281 | } 1282 | } --------------------------------------------------------------------------------