Part 3: Integrate with a DynamoDB table¶
Now that we have a Lambda function that can detect labels in an image, let’s integrate a DynamoDB table so we can query information across the various images stored in our bucket. So instead of returning the labels, the Chalice application will store the items in a DynamoDB table.
For this section, we will be doing the following to integrate the DynamoDB table:
Copy over boilerplate files¶
Copy over files needed for integrating the DynamoDB table into the application
Instructions¶
Using
media-queryas the current working directory, copy thedb.pymodule into thechalicelibpackage:$ cp ../chalice-workshop/code/media-query/03-add-db/chalicelib/db.py chalicelib/
Using
media-queryas the current working directory, copy over an updated version of theresources.jsonfile:$ cp ../chalice-workshop/code/media-query/03-add-db/resources.json .
Verification¶
Ensure the structure of the
media-querydirectory includes the following files and directories:$ tree -a . ├── .chalice │ ├── config.json │ └── policy-dev.json ├── .gitignore ├── app.py ├── chalicelib │ ├── __init__.py │ ├── db.py │ └── rekognition.py ├── recordresources.py ├── requirements.txt └── resources.json
Note there will be more files listed with
treeassuming you already deployed the application once. However, the files listed from thetreeoutput above are required.Ensure the contents of the
resources.jsonis now the following:$ cat resources.json { "Outputs": { "MediaBucketName": { "Value": { "Ref": "MediaBucket" } }, "MediaTableName": { "Value": { "Ref": "MediaTable" } } }, "Resources": { "MediaBucket": { "Type": "AWS::S3::Bucket" }, "MediaTable": { "Properties": { "AttributeDefinitions": [ { "AttributeName": "name", "AttributeType": "S" } ], "KeySchema": [ { "AttributeName": "name", "KeyType": "HASH" } ], "ProvisionedThroughput": { "ReadCapacityUnits": 5, "WriteCapacityUnits": 5 } }, "Type": "AWS::DynamoDB::Table" } } }
Create a DynamoDB table¶
Create a DynamoDB table to store and query information about images in the S3 bucket.
Instructions¶
Use the AWS CLI and the
resources.jsonCloudFormation template to redeploy themedia-queryCloudFormation stack and create a new DynamoDB$ aws cloudformation deploy --template-file resources.json --stack-name media-query
Verification¶
Retrieve and store the name of the DynamoDB table using the AWS CLI:
$ MEDIA_TABLE_NAME=$(aws cloudformation describe-stacks --stack-name media-query --query "Stacks[0].Outputs[?OutputKey=='MediaTableName'].OutputValue" --output text)
Ensure the existence of the table using the
describe-tableCLI command:$ aws dynamodb describe-table --table-name $MEDIA_TABLE_NAME { "Table": { "AttributeDefinitions": [ { "AttributeName": "name", "AttributeType": "S" } ], "TableName": "media-query-MediaTable-10QEPR0O8DOT4", "KeySchema": [ { "AttributeName": "name", "KeyType": "HASH" } ], "TableStatus": "ACTIVE", "CreationDateTime": 1531769158.804, "ProvisionedThroughput": { "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 5, "WriteCapacityUnits": 5 }, "TableSizeBytes": 0, "ItemCount": 0, "TableArn": "arn:aws:dynamodb:us-west-2:123456789123:table/media-query-MediaTable-10QEPR0O8DOT4", "TableId": "00eebe92-d59d-40a2-b5fa-32e16b571cdc" } }
Integrate the DynamoDB table¶
Integrate the newly created DynamoDB table into the Chalice application.
Instructions¶
Save the DynamoDB table name as an environment variable in the Chalice application by running the
recordresources.pyscript:$ python recordresources.py --stack-name media-query
Import
osand thechalicelib.dbmodule in yourapp.pyfile:
1 2 3 4 5 6 | import os
import boto3
from chalice import Chalice
from chalicelib import db
from chalicelib import rekognition
|
Add a helper function for instantiating a
db.DynamoMediaDBclass using the DynamoDB table name stored as the environment variableMEDIA_TABLE_NAME:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import os
import boto3
from chalice import Chalice
from chalicelib import db
from chalicelib import rekognition
app = Chalice(app_name='media-query')
_MEDIA_DB = None
_REKOGNITION_CLIENT = None
def get_media_db():
global _MEDIA_DB
if _MEDIA_DB is None:
_MEDIA_DB = db.DynamoMediaDB(
boto3.resource('dynamodb').Table(
os.environ['MEDIA_TABLE_NAME']))
return _MEDIA_DB
|
Update the
detect_labels_on_imageLambda function to save the image along with the detected labels to the database:@app.lambda_function() def detect_labels_on_image(event, context): bucket = event['Bucket'] key = event['Key'] labels = get_rekognition_client().get_image_labels(bucket=bucket, key=key) get_media_db().add_media_file(key, media_type=db.IMAGE_TYPE, labels=labels)
Verification¶
Ensure the contents of the
config.jsoncontains environment variables forMEDIA_TABLE_NAME:$ cat .chalice/config.json { "version": "2.0", "app_name": "media-query", "stages": { "dev": { "api_gateway_stage": "api", "autogen_policy": false, "environment_variables": { "MEDIA_TABLE_NAME": "media-query-MediaTable-10QEPR0O8DOT4", "MEDIA_BUCKET_NAME": "media-query-mediabucket-fb8oddjbslv1" } } } }Note that the
MEDIA_BUCKET_NAMEwill be present as well in the environment variables. It will be used in the next part of the tutorial.Ensure the contents of the
app.pyfile is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import os
import boto3
from chalice import Chalice
from chalicelib import db
from chalicelib import rekognition
app = Chalice(app_name='media-query')
_MEDIA_DB = None
_REKOGNITION_CLIENT = None
def get_media_db():
global _MEDIA_DB
if _MEDIA_DB is None:
_MEDIA_DB = db.DynamoMediaDB(
boto3.resource('dynamodb').Table(
os.environ['MEDIA_TABLE_NAME']))
return _MEDIA_DB
def get_rekognition_client():
global _REKOGNITION_CLIENT
if _REKOGNITION_CLIENT is None:
_REKOGNITION_CLIENT = rekognition.RekognitonClient(
boto3.client('rekognition'))
return _REKOGNITION_CLIENT
@app.lambda_function()
def detect_labels_on_image(event, context):
bucket = event['Bucket']
key = event['Key']
labels = get_rekognition_client().get_image_labels(bucket=bucket, key=key)
get_media_db().add_media_file(key, media_type=db.IMAGE_TYPE, labels=labels)
|
Redeploy the Chalice application¶
Deploy the updated Chalice application.
Instructions¶
Run
chalice deploy:$ chalice deploy Creating deployment package. Updating policy for IAM role: media-query-dev-detect_labels_on_image Updating lambda function: media-query-dev-detect_labels_on_image Resources deployed: - Lambda ARN: arn:aws:lambda:us-west-2:123456789123:function:media-query-dev-detect_labels_on_image
Verification¶
Run
chalice invokewith thesample-event.jsonon the updateddetect_labels_on_imageLambda function:$ chalice invoke --name detect_labels_on_image < sample-event.json null
Use the
get-itemCLI command to ensure thesample.jpgdata was populated in the DynamoDB table:$ aws dynamodb get-item --table-name $MEDIA_TABLE_NAME \ --key '{"name": {"S": "sample.jpg"}}' { "Item": { "name": { "S": "sample.jpg" }, "labels": { "L": [ { "S": "Animal" }, { "S": "Canine" }, { "S": "Dog" }, { "S": "German Shepherd" }, { "S": "Mammal" }, { "S": "Pet" }, { "S": "Collie" } ] }, "type": { "S": "image" } } }