Step 7: Pin Thumbnails - solargis/cdk-workshop GitHub Wiki

In this step we will add asynchronous resizing of pin images into thumbnails, to be displayed inside of pin markers in the map.

We will use S3 notification from image bucket as event source for thumbnail lambda, so each saved pin images will be converted into thumbnail. We will save thumbnails to the same S3 bucket as images.

For resizing images we will use sharp image manipulation library. Sharp library uses binary dependencies, which has to be compiled in Lambda-compatible environment to work in Lambda properly. For that purpose we have prepared the sharp library as precompiled Lambda layer.

Thumbnail lambda code, angular code and sharp layer is provided, we will setup the cloud resources in CDK code and small update in webpack build.

Fast-forward to this step (optional)

git checkout step-7/pin-thumbnail
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 here
  • git commit -a -m "my change" - commit all changes to local branch
  • git reset --hard HEAD - remove all local changes

Preparation (skip if fast-forwarded)

Add npm dependencies:

npm install --save sharp del @aws-cdk/aws-s3-notifications
npm install --save-dev @types/sharp

Extract code from step7-pin-thumbnail.zip to ./

./lib/api/thumbnail-lambda.ts                          - resize image Lambda handler
./lib/api/utils/s3.utils.ts                            - handling also thumbnails in S3
./lib/layers/sharp_layer.zip                           - sharp library as Lambda layer
./lib/shared/types/pin.types.ts                        - added thumbnail to Pin type
./lib/web/src/app/app.module.ts                        - updated root app modue
./lib/web/src/app/components/map.component.ts          - updated map component
./lib/web/src/app/components/pin-marker.component.html - template for thumbnail marker
./lib/web/src/app/components/pin-marker.component.scss - styles for thumbnail map marker
./lib/web/src/app/components/pin-marker.component.ts   - thumbnail map marker component
./lib/web/src/app/utils/leaflet.utils.ts               - custom icon for Leaflet

4.1 Thumbnail lambda setup

Add thumbnail lambda into webpack API config: ./lib/webpack.api.js

entry: {
  'hello-lambda': './lib/api/hello-lambda.ts',
  'pin-lambda': './lib/api/pin-lambda.ts',
  'thumbnail-lambda': './lib/api/thumbnail-lambda.ts'
},

Exclude sharp library from webpack build: ./lib/webpack.api.js

const layerModules = ['sharp'];

// ...
externals: [...awsModules, ...layerModules],

Define sharp library as Lambda layer: ./cdk/cdk-workshop-stack.ts

import { Code, Function, LayerVersion, Runtime } from '@aws-cdk/aws-lambda';

// ...

const sharpLayer = new LayerVersion(this, `SharpLayer_${props.userName}`, {
  code: Code.fromAsset('lib/layers/sharp_layer.zip'),
  compatibleRuntimes: [Runtime.NODEJS_10_X],
  license: 'Apache-2.0',
  description: 'Sharp image processing library v.0.23.1'
});

sharp library uses libvips binary library, which needs to be pre-compiled for Lambda environment - as Lambda layer

Define thumbnail Lambda handler: ./cdk/cdk-workshop-stack.ts

import { CfnOutput, Construct, Duration, RemovalPolicy, Stack, StackProps } from '@aws-cdk/core';

// ...

const thumbnailHandler = new Function(this, 'ThumbnailHandler', {
  code: apiCode,
  runtime: Runtime.NODEJS_10_X,
  handler: 'thumbnail-lambda.handler',
  layers: [sharpLayer],
  memorySize: 1536,
  timeout: Duration.seconds(60),
  environment: {
    IMAGE_BUCKET: imageBucket.bucketName,
    PIN_TABLE: pinTable.tableName
  }
});
imageBucket.grantReadWrite(thumbnailHandler);
pinTable.grantReadWriteData(thumbnailHandler);

Hook image upload event in S3 bucket to thumbnail lambda: ./cdk/cdk-workshop-stack.ts

import { Bucket, EventType } from '@aws-cdk/aws-s3';
import { LambdaDestination } from '@aws-cdk/aws-s3-notifications';

// ...

imageBucket.addEventNotification(
  EventType.OBJECT_CREATED,
  new LambdaDestination(thumbnailHandler),
  { prefix: 'original' }
);

Build and deploy:

npm run build
cdk deploy

Test

  • Open app in browser and pin some images, thumbnails will be generated asynchronously

Next Step 8: Local development environment