Published on

Create your own QR Code Generator with AWS and AWS CDK! - Creating The API

Authors
  • avatar
    Name
    Katherine Moreno
    Twitter

Introduction

In my efforts trying to keep challenguing myself in my journey to improve my AWS skills I found the challengue from Rishab Kumar to setup a QR Code generator. On his video, Rishab give us the architecture to start the project.

alt text
I decided to give it a bit Twist and instead of using Function Lambda URLs, expose the Lambda through API Gateway. alt text

How I did it

To generate the qr code we use the qrcode library and to generate unique filenames of the objects we use the uuid library.

# This lambda receives the URL as parameter
import boto3
import json
import qrcode
import uuid
import io

import os

s3 = boto3.client("s3")
region = os.environ["REGION"]
bucket_name = os.environ["BUCKET_NAME"]


def handler(event, context):
    randomUuid = str(uuid.uuid4)

    body = event["body"]
    parsed_body = json.loads(body)

    url = parsed_body["url"]

    # Generate QR code
    img = qrcode.make(url)
    img_bytes = io.BytesIO()
    img.save(img_bytes)
    img_bytes = img_bytes.getvalue()

    # Generate a unique filename
    filename = randomUuid + ".png"

    # Upload the object to S3
    s3.put_object(
        Body=img_bytes,
        Bucket=bucket_name,
        Key=filename,
        ContentType="image/png",
        ACL="public-read",
    )

    url_code = f"https://{bucket_name}.s3.{region}.amazonaws.com/{filename}"
    return {
        "statusCode": 200,
        "body": json.dumps(
            {
                "message": "QR code generated and uploaded to S3 bucket successfully!",
                "qr_code_url": url_code,
            }
        ),
        "headers": {
            "Access-Control-Allow-Headers": "Content-Type",
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "*",
        },
    }

As we are using as external dependency the library qrcode we need to define a requirements.txt. More information about how to bundle external dependencies here.

qrcode==7.4.2

and in our Stack API

from aws_cdk import (
    Stack,
    aws_lambda as lambda_,
    aws_apigateway as apigateway,
    aws_s3 as s3,
)

from aws_cdk.aws_lambda_python_alpha import (
    PythonFunction,
) 

from constructs import Construct

class QrGeneratorStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # ------------------------ Backend -------------------------------------#

        # Create the S3 Bucket with ACL Configuration
        bucket = s3.Bucket(
            self,
            "Bucket",
            block_public_access=s3.BlockPublicAccess(
                block_public_acls=False,
                block_public_policy=False,
                ignore_public_acls=False,
                restrict_public_buckets=False,
            ),
            object_ownership=s3.ObjectOwnership.OBJECT_WRITER,
        )

        # Create the lambda
        create_qr_lambda = PythonFunction(
            self,
            "CreateQrCodeLambda",
            function_name="createQrCodeLambda",
            runtime=lambda_.Runtime.PYTHON_3_11,
            index="create_qr.py",  # Path to the directory with the Lambda function code
            handler="handler",  # Handler of the Lambda function
            entry="./lambda",
            environment={
                "REGION": self.region,
                "BUCKET_NAME": bucket.bucket_name,
            },
            description="Lambda for creating the QR code",
        )

        #Grant permissions to the Lambda
        bucket.grant_read_write(create_qr_lambda)
        bucket.grant_put_acl(create_qr_lambda)

        # Define the API Gateway
        api = apigateway.RestApi(self, "ApiGatewayQR", rest_api_name="RestAPI QR")

        qr_code_integration = apigateway.LambdaIntegration(create_qr_lambda)

        qr = api.root.add_resource("qr")
        
        qr.add_method("POST", qr_code_integration)
The most complicated part was to configure the ACL but this thread on Github help me to condigure it. We test it on Postman and Voila! We've our endpoint which returns a url alt text and if we click on the url it give us the image of the Generated QR Code! alt text

Epilogue

We've learn to create an API which generates qr codes, but is not enough. Keep reading in my following post how did I host the website with S3 and Cloudfront