UNPKG

cfn-forge

Version:

CloudFormation deployment automation tool with git-based workflows

376 lines (327 loc) 10.3 kB
name: serverless-api description: A serverless API template with Lambda functions and API Gateway version: 1.0.0 author: CFN-Forge cfnForgeVersion: 1.0.0 variables: projectName: prompt: "Project name" default: "my-serverless-api" description: prompt: "Project description" default: "A serverless API built with AWS Lambda and API Gateway" lambdaRuntime: prompt: "Lambda runtime" default: "nodejs18.x" options: ["nodejs18.x", "nodejs20.x", "python3.9", "python3.10", "python3.11"] memorySize: prompt: "Lambda memory size (MB)" default: "128" type: "number" files: include: - "**/*" exclude: - "template.yaml" - ".git/**" - "node_modules/**" structure: cloudformation.yaml: | AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: {{description}} Parameters: Environment: Type: String Default: dev AllowedValues: [dev, staging, prod] Description: Environment name Globals: Function: Timeout: 30 Runtime: {{lambdaRuntime}} MemorySize: {{memorySize}} Environment: Variables: NODE_ENV: !Ref Environment LOG_LEVEL: INFO Resources: # API Gateway ApiGateway: Type: AWS::Serverless::Api Properties: StageName: !Ref Environment Cors: AllowMethods: "'GET,POST,PUT,DELETE,OPTIONS'" AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" AllowOrigin: "'*'" # Lambda Functions HelloWorldFunction: Type: AWS::Serverless::Function Properties: FunctionName: !Sub "${AWS::StackName}-hello-world" CodeUri: src/handlers/hello-world/ Handler: index.handler Events: HelloWorldApi: Type: Api Properties: RestApiId: !Ref ApiGateway Path: /hello Method: GET CreateItemFunction: Type: AWS::Serverless::Function Properties: FunctionName: !Sub "${AWS::StackName}-create-item" CodeUri: src/handlers/create-item/ Handler: index.handler Policies: - DynamoDBCrudPolicy: TableName: !Ref ItemsTable Events: CreateItemApi: Type: Api Properties: RestApiId: !Ref ApiGateway Path: /items Method: POST GetItemsFunction: Type: AWS::Serverless::Function Properties: FunctionName: !Sub "${AWS::StackName}-get-items" CodeUri: src/handlers/get-items/ Handler: index.handler Policies: - DynamoDBReadPolicy: TableName: !Ref ItemsTable Events: GetItemsApi: Type: Api Properties: RestApiId: !Ref ApiGateway Path: /items Method: GET # DynamoDB Table ItemsTable: Type: AWS::DynamoDB::Table Properties: TableName: !Sub "${AWS::StackName}-items" BillingMode: PAY_PER_REQUEST AttributeDefinitions: - AttributeName: id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH Outputs: ApiUrl: Description: API Gateway URL Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/${Environment}" Export: Name: !Sub "${AWS::StackName}-ApiUrl" ItemsTableName: Description: DynamoDB Items Table Name Value: !Ref ItemsTable Export: Name: !Sub "${AWS::StackName}-ItemsTable" .cfn-forge.yaml: | project: name: {{projectName}} description: {{description}} type: serverless-api environments: dev: stackName: "{{projectName}}-dev" template: cloudformation.yaml region: us-east-1 parameters: Environment: dev staging: stackName: "{{projectName}}-staging" template: cloudformation.yaml region: us-east-1 parameters: Environment: staging prod: stackName: "{{projectName}}-prod" template: cloudformation.yaml region: us-east-1 parameters: Environment: prod deployment: packagingBucket: "{{projectName}}-deployment-artifacts" createBucket: true git: watchBranches: ["main", "develop"] deployOnPush: true package.json: | { "name": "{{projectName}}", "version": "1.0.0", "description": "{{description}}", "main": "src/handlers/hello-world/index.js", "scripts": { "start": "sam local start-api", "build": "sam build", "deploy": "cfn-forge deploy", "watch": "cfn-forge watch", "validate": "cfn-forge validate", "test": "jest", "test:watch": "jest --watch", "lint": "eslint src/" }, "dependencies": { "aws-sdk": "^2.1490.0" }, "devDependencies": { "jest": "^29.0.0", "eslint": "^8.0.0" }, "keywords": ["serverless", "aws", "lambda", "api-gateway"], "author": "{{author}}", "license": "MIT" } src/handlers/hello-world/index.js: | exports.handler = async (event) => { console.log('Event:', JSON.stringify(event, null, 2)); return { statusCode: 200, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, body: JSON.stringify({ message: 'Hello from {{projectName}}!', timestamp: new Date().toISOString(), environment: process.env.NODE_ENV }) }; }; src/handlers/create-item/index.js: | const AWS = require('aws-sdk'); const { v4: uuidv4 } = require('uuid'); const dynamodb = new AWS.DynamoDB.DocumentClient(); const tableName = process.env.ITEMS_TABLE || '{{projectName}}-dev-items'; exports.handler = async (event) => { console.log('Event:', JSON.stringify(event, null, 2)); try { const body = JSON.parse(event.body || '{}'); const item = { id: uuidv4(), ...body, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }; await dynamodb.put({ TableName: tableName, Item: item }).promise(); return { statusCode: 201, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, body: JSON.stringify({ message: 'Item created successfully', item }) }; } catch (error) { console.error('Error:', error); return { statusCode: 500, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, body: JSON.stringify({ message: 'Internal server error', error: error.message }) }; } }; src/handlers/get-items/index.js: | const AWS = require('aws-sdk'); const dynamodb = new AWS.DynamoDB.DocumentClient(); const tableName = process.env.ITEMS_TABLE || '{{projectName}}-dev-items'; exports.handler = async (event) => { console.log('Event:', JSON.stringify(event, null, 2)); try { const result = await dynamodb.scan({ TableName: tableName }).promise(); return { statusCode: 200, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, body: JSON.stringify({ items: result.Items, count: result.Count }) }; } catch (error) { console.error('Error:', error); return { statusCode: 500, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, body: JSON.stringify({ message: 'Internal server error', error: error.message }) }; } }; README.md: | # {{projectName}} {{description}} ## Quick Start 1. Install dependencies: ```bash npm install ``` 2. Deploy to AWS: ```bash cfn-forge deploy ``` 3. Start local development: ```bash cfn-forge watch ``` ## API Endpoints - `GET /hello` - Hello world endpoint - `GET /items` - Get all items - `POST /items` - Create a new item ## Project Structure ``` {{projectName}}/  src/   handlers/   hello-world/   create-item/   get-items/  cloudformation.yaml  .cfn-forge.yaml  package.json ``` ## Deployment This project uses CFN-Forge for deployment. The configuration is in `.cfn-forge.yaml`. ### Environments - **dev**: Development environment - **staging**: Staging environment - **prod**: Production environment ### Commands - `cfn-forge deploy` - Deploy to the default environment - `cfn-forge deploy --env prod` - Deploy to production - `cfn-forge watch` - Watch for changes and auto-deploy - `cfn-forge validate` - Validate CloudFormation template hooks: postInstall: - type: npm command: install