Step 8: Local development environment - solargis/cdk-workshop GitHub Wiki
In this step we will configure all the environment to run on local machine. So we can easily test and develop the application without the build-deploy roundtrip to the cloud.
For that purpose we will use Serverless framework and its plugins to setup AWS resources locally. With hot-reload features of Angular CLI and Webpack we will configure a development mode supporting hot-code reload for both lambda code and angular code.
NOTE: Java JRE 1.8+ is required to run AWS DynamoDB Local
Fast-forward to this step (optional)
git checkout step-8/local-env
npm install
NOTE: if you have uncommited work in project repository it is not possible to checkout new Git branch, you have 3 options:
git stash
- move all local changes into a 'drawer', more info heregit commit -a -m "my change"
- commit all changes to local branchgit reset --hard HEAD
- remove all local changes
8.1 Configure local Serverless
Add npm dependencies:
npm install --save-dev concurrently serverless serverless-dynamodb-local serverless-offline serverless-s3-local
Add Serverless configuration: ./serverless.yml
service: cdk-workshop-local
plugins:
- serverless-dynamodb-local
- serverless-s3-local
- serverless-offline
provider:
name: aws
runtime: nodejs10.x
region: eu-west-1
stage: local
environment:
S3_ENDPOINT: 'http://localhost:9000'
DYNAMODB_ENDPOINT: 'http://localhost:8000'
IMAGE_BUCKET: ImageBucketLocal
PIN_TABLE: PinLocal
TEMP_DIR: '.local/tmp'
custom:
serverless-offline:
port: 4000
dynamodb:
stages:
- local
start:
port: 8000
dbPath: .local/dynamo
sharedDb: true
migrate: true
s3:
host: 0.0.0.0
port: 9000
directory: .local/s3
resources:
Resources:
imageBucketLocal:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:provider.environment.IMAGE_BUCKET}
pinTableLocal:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:provider.environment.PIN_TABLE}
AttributeDefinitions:
- AttributeName: pointUrl
AttributeType: S
KeySchema:
- AttributeName: pointUrl
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
functions:
hello:
handler: 'dist/api/hello-lambda.handler'
events:
- http:
method: get
path: /hello
cors: true
pin:
handler: 'dist/api/pin-lambda.handler'
events:
- http:
method: any
path: /pin
cors: true
- http:
method: any
path: /pin/{pointUrl}
cors: true
thumbnail:
handler: 'dist/api/thumbnail-lambda.handler'
events:
- s3:
bucket: ${self:provider.environment.IMAGE_BUCKET}
event: s3:ObjectCreated:*
rules:
- prefix: original
Create empty folders for local resources
.local/dynamo
.local/s3
.local/tmp
Add npm scripts for local development: ./package.json
"dev": "concurrently -c gray,yellow,green npm:api:watch npm:api:serve npm:web:serve --kill-others-on-fail",
"api:watch": "npm run api:build -- --watch --progress",
"api:serve": "sls dynamodb install && sls offline start",
"web:serve": "ng serve"
Set local API url (http://localhost:4000) as API base: ./lib/web/src/index.html
<meta name="x-api-base" content="http://localhost:4000/">
8.2 Support local endpoints in lambda code
Update Lambda code to support local S3 endpoint: ./lib/api/utils/s3.utils.ts
const localEndpoint = process.env.S3_ENDPOINT as any;
const s3 = new S3(localEndpoint && {
accessKeyId: 'S3RVER',
secretAccessKey: 'S3RVER',
region: 'local',
endpoint: localEndpoint
});
// ...
function getPublicUrl(s3key: string): string {
return localEndpoint
? `${localEndpoint}/${imageBucket}/${s3key}`
: `https://${imageBucket}.s3-${region}.amazonaws.com/${s3key}`;
}
function getDownloadUrl(s3key: string, name: string) {
return localEndpoint
? `${localEndpoint}/${imageBucket}/${s3key}`
: s3.getSignedUrl('getObject', {
Bucket: imageBucket,
Key: s3key,
ResponseContentDisposition: `attachment; filename="${name}"`
});
}
Update Lambda code to support local DynamoDB endpoint:
./lib/api/pin-lambda.ts
const dynamo = new DynamoDB.DocumentClient({
endpoint: process.env.DYNAMODB_ENDPOINT
});
./lib/api/thumbnail-lambda.ts
const tempDir = process.env.TEMP_DIR || '/tmp';
const dynamo = new DynamoDB.DocumentClient({
endpoint: process.env.DYNAMODB_ENDPOINT
});
Test
Launch local development environment:
npm run dev
- Open app in browser: http://localhost:4200
- Test local API: http://localhost:4000
- Make changes in server code or lambda code, changes get applied