# Learning AWS Lambda, API Gateway, and S3 by Building Your Own QR Code Generation API

In this tutorial, we will develop a custom QR code generator API and then integrate it into a basic website.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698772065283/45772850-c1c9-49e8-8931-36bb49b459b6.gif align="center")

We'll build the API using Node.js and deploy it on AWS Lambda. The API endpoints will be established through API Gateway, and the generated QR codes will be stored in Amazon S3. The only requirement is having an AWS account. If you're within the free tier, following this tutorial should incur no costs, as we'll stay within the free tier limits. However, it's important to delete all AWS resources once you're done practicing to prevent any unexpected charges.

---

AWS Lambda is a serverless compute service provided by AWS (Amazon Web Services) that allows developers to run code in response to events without having to manage servers or runtime environments. Lambda Supports lots of Runtime environments like Node.js, Python, Go, Ruby, Java, .NET etc. It supports custom runtime environments also. You only pay for the compute time you consume - there is no charge when your code is not running.

Under Free Tier AWS Gives 1,000,000 free requests per month which is 3.2 million seconds of free compute time per month for 12 months.

## Step 1: Creating S3 Bucket

We will be creating an S3 bucket. and making content inside it publically accessible so we can access our generated QR codes.

Login into AWS and search s3 in the search bar then click on the first result as shown in the image.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698763680300/e8e2590c-f706-4538-b4fa-bd5aa4515933.png align="center")

Click on Create Bucket

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698763737106/064dbfb5-d0ab-4efe-9819-41981628d8f3.png align="center")

Now Enter the Bucket name it must be unique. Keep all options as default. and then click on the "create bucket" button at the bottom.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698763810857/1b7ee744-070a-4aa7-98e2-07d6c6c5479c.png align="center")

Now After Your bucket is created click on the "Permissions" tab. Click on the Edit button on "Block public access".

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698763916446/f5830657-5850-4454-adb3-6f17abb1fc5b.png align="center")

uncheck all options and click on "Save Changes". You will be asked to confirm. type confirm.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698764009642/5e5c23d4-fb46-4561-9279-2608b82836ef.png align="center")

Now Move down and click on Edit button in "Bucket policy".

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698764101055/df84c6d8-ae53-459a-9751-8fddf964f649.png align="center")

Update Bucket Policy like below. Keep in mind to add Your Bucket ARN. You can take it just from above.

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "<Your ARN>/*"
    }
  ]
}
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698764209695/67840c69-423a-47ec-9af0-39220570e45c.png align="center")

Now Click on "Save Changes"  
Now Our S3 Bucket is ready. All files put inside this bucket now will be publically accessible.

## Step 2: Creating a Lambda Function

Search lambda in the search bar then click on the first result as shown in the image.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698761537367/3ecdfe6f-6cbb-443e-a695-51cc48aea5ae.png align="center")

Now Click on Create Function

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698761675684/7b494b79-007a-4d48-87e4-b487a7d0341f.png align="center")

Then Select the First Option "Author from scratch" and then Enter the Function name. Also, Runtime should be selected as Node.js. Keep Everything default. and Just click on the "Create Function" button.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698761717180/5085b7f3-a18b-4ddb-a67f-1f4c2c555199.png align="center")

You Will come across a window like below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698761898791/757eed7c-f190-4901-a451-de7295e6c17c.png align="center")

You can explore this window to learn more.

Go to link [https://github.com/Anujsd/lambda-qr-code](https://github.com/Anujsd/lambda-qr-code)  
And Clone this Repo in your PC.  
Open that in your Favourite IDE I will be using vs code.  
Open index.mjs go to line number 9 and update the bucket name with your bucket name we just created.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698764856868/e2b06c90-4c92-4da3-8242-83fc330a5750.png align="center")

Now Run the Command "npm install" to install node dependencies

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698764992349/e3a89018-6858-438d-b482-e1ccef23aeb2.png align="center")

Now We are going to create a ZIP of this whole "lambda-qr-code" folder.  
For Windows open it in File Explorer select all, right-click and click on compress to zip.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698765100952/0a6f3425-a3e4-4f2c-bcc3-181c6c29452e.png align="center")

name zip file "lambda-qr-code".  
For the Sake of this tutorial, we will be uploading code using zip.  
This ZIP file contains all code and node modules required for the lambda function. As we are using custom packages we need to upload node modules in zip format. otherwise, we could have directly written code on the web interface.

Now to upload this ZIP go to lambda in AWS in the "code" section and click on "upload from".

select option ".zip file" and upload that zip file.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698762353241/9ef66b8c-0155-46ab-94f6-de36c4228bc6.png align="center")

After Uploading the File You will see an interface like below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698762433474/a15b7b31-19ec-4088-83a6-f3b67fada244.png align="center")

The code won't be visible in the web interface because the file is too large; however, it's quite straightforward, and you can view it below.

```javascript
import AWS from 'aws-sdk';
import QRCode from 'qrcode';

// Configure AWS SDK
AWS.config.update({ region: 'us-east-1' });
const s3 = new AWS.S3();

// Define S3 bucket and key
const bucketName = '<s3 bucket name>';
const key = `qr-codes/${Date.now()}.png`;

export const handler = async (event) => {
  console.log(JSON.stringify(event));

  // Process POST request
  try {
    let requestBody;
    if (typeof event.body === 'string') {
      requestBody = JSON.parse(event.body);
    } else {
      requestBody = event.body; // Assuming it's already parsed
    }

    const { url } = requestBody;

    if (!url) {
      return {
        statusCode: 400,
        body: JSON.stringify({ message: 'URL is required', body: requestBody }),
      };
    }

    // Generate QR code
    const qrCodeBuffer = await QRCode.toBuffer(url);

    // Upload QR code to S3
    await s3
      .putObject({
        Bucket: bucketName,
        Key: key,
        Body: qrCodeBuffer,
        ContentType: 'image/png',
      })
      .promise();

    // Construct the public URL of the QR code
    const publicUrl = `https://${bucketName}.s3.amazonaws.com/${key}`;

    // Return response with CORS headers
    return {
      statusCode: 200,
      body: JSON.stringify({ qrCodeUrl: publicUrl }),
    };
  } catch (error) {
    console.error('Error generating QR code:', error);
    return {
      statusCode: 500,
      body: JSON.stringify({ message: 'Internal Server Error' }),
    };
  }
};
```

Now We will be giving our lambda function permission to add generated QR in s3.

for that go to the "Configuration" Tab then "Permissions" and click on the "Role name" link. It will be opened in a new tab.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698768689900/269788a5-d16b-47c5-9bf4-b94c18768ebf.png align="center")

Now in a newly opened window. click on "Add permissions" and then "Attach policies".

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698768783421/9e0f926e-7426-49c9-8861-8c952b844ae9.png align="center")

a new window will be opened. Search "s3" in that and select "[AmazonS3FullAccess](https://us-east-1.console.aws.amazon.com/iamv2/home#/policies/details/arn%3Aaws%3Aiam%3A%3Aaws%3Apolicy%2FAmazonS3FullAccess)" policy. and click on the "add permissions" button at the bottom.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698768860667/d497edc2-7464-4191-be03-20f23466b6ac.png align="center")

Now go to lambda Function.

We will be testing If it's working or not.  
Click on the "Test" Section. Select options like below and add below JSON which is our test payload.

```json
{
  "body": {
    "url": "https://anujdube.com/"
  }
}
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698762937086/bb144d31-8d48-476b-8534-94f01155994d.png align="center")

Click on "Save" and then click on the "Test" button.  
After Successful execution, you will see the output like below. To see detailed logs you can click on the "logs" link.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769022990/44e65374-3713-4f65-bb64-2d213a0326cb.png align="center")

Now Our lambda function is ready we are going to add an API gateway to this lambda function.

## Step 3: Attaching API gateway to lambda function

Search API Gateway in the search bar then click on the first result as shown in the image.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769249545/a0d7ac82-fb1c-4d9a-b46b-4e11375b8b83.png align="center")

after opening it. Click on the "build" option in HTTP API.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769299119/af25091f-5670-4e66-9bc6-1861742f6c3f.png align="center")

In "Intergrations" select our lambda function as shown below. and add name to API.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769372592/58afa018-d823-4491-a6cd-68587c8710ba.png align="center")

click on next. in routes. add a POST route like below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769431464/b2a53d9b-b43e-4572-a956-5bddb08c6113.png align="center")

Now Click on next. keep everything default. and click on the "Create" button.

You will see your API created like below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769612496/eccdcf50-8554-428c-ad27-bf87796913ac.png align="center")

Now open your API. On the left-hand side click on the section after "VPC links".

and in there you can see the invoke URL. this is your API URL.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769662116/73aff34b-1662-4126-856f-b5c8ae47cbea.png align="center")

You can use this URL and do a POST request using POSTMAN. It will be successful.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769788090/dbff412b-8205-4770-b4c3-70e2f3b9aeee.png align="center")

But if you try to use this URL in any application you might get CORS errors like below.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769949072/4ee473e6-3de6-4ce0-806d-3427fd2e7cc3.png align="center")

To resolve these errors click on CORS on the left-hand side. and click on "configure"

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698769981198/8bdf30c0-1140-4cdd-9f93-894e555ccaf5.png align="center")

Add values as below and click on "Save"

**Access-Control-Allow-Origin** : *\**

**Access-Control-Allow-Headers** : *Content-Type, x-requested-with*

**Access-Control-Allow-Methods** : *OPTIONS, POST*

At the moment, we are permitting access from all origins. However, for enhanced security in a production environment, it's advisable to restrict access to just your domain name.

Click on the "save" button.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698770293550/641a1dcc-9022-40d9-81ca-be414d80014e.png align="center")

Now You will not face any CORS Errors While using your API in any app.

## Step 4: Integrating the Created API into a Website

Now we will be trying to use the created API in a simple app.

Click on the below link and clone the repo  
[https://github.com/Anujsd/qr-code-front-end](https://github.com/Anujsd/qr-code-front-end)  
it just has 3 files.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698770519594/924b8bd2-b94f-4f34-b847-44709c9da54e.png align="center")

open script.js

and on line number 1. update your API endpoint

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698770577898/c1ee76ac-c1f4-439f-b398-03b05db39ca8.png align="center")

now if you open index.html

you will see UI like below

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698770628869/1bbb0ec2-3b00-42c3-a8e6-f95fb0d9ef71.png align="center")

enter any link to shorten and you will see a QR code generated for that link  
you can test if the QR code is correct or not.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1698770703619/71d4fe76-6b9a-4c74-9a57-d06b6d17ac07.png align="center")

Now You can host this website online if needed.

---

In this way, We developed our custom QR Code generation API utilizing AWS Lambda. If you encounter any issues or spot any errors in the article, please don't hesitate to contact me.
