<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ike Gabriel Yuson</title>
    <description>The latest articles on DEV Community by Ike Gabriel Yuson (@ikeman09).</description>
    <link>https://dev.to/ikeman09</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F804813%2F22afd40f-117a-4a86-a24d-62555e051599.jpeg</url>
      <title>DEV Community: Ike Gabriel Yuson</title>
      <link>https://dev.to/ikeman09</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ikeman09"/>
    <language>en</language>
    <item>
      <title>Serverless way of uploading pictures to an S3 Bucket</title>
      <dc:creator>Ike Gabriel Yuson</dc:creator>
      <pubDate>Mon, 06 Jun 2022 16:49:40 +0000</pubDate>
      <link>https://dev.to/ikeman09/serverless-way-of-uploading-pictures-to-an-s3-bucket-acb</link>
      <guid>https://dev.to/ikeman09/serverless-way-of-uploading-pictures-to-an-s3-bucket-acb</guid>
      <description>&lt;p&gt;In creating full-stack applications, there will come a time when a developer undergoes R&amp;amp;D of how to store pictures and files and dynamically allocate them to a specified user. Cases such as profile pictures, photo uploads and other dynamic files that can be transmitted as binary data that are unique to each user are some of the entry-level challenges a developer will experience. And one of the most efficient way of handling these things are through cloud services such as Amazon S3.&lt;/p&gt;

&lt;p&gt;Uploading a file or photo to an Amazon S3 bucket is easy in a server-full architect-ed platform. In the case of hosting a backend service in an EC2 platform, one way to upload a file or photo is to upload the image to the server and then the server pushes the image to the S3 bucket. The client then have to call a get request to the server if it wishes to get a resource from the S3 bucket. Another way of uploading is to immediately upload the the image from the frontend to the S3 bucket. This way, the server does not have to handle the image data being passed on from backend to the S3 bucket.&lt;/p&gt;

&lt;p&gt;However, if your choice of architecture is a serverless one and that you want the uploading of an image to an S3 bucket be handled by your lambda functions then there is a way for that too! This article would be a step by step guide of how to upload images through lambda functions! &lt;/p&gt;

&lt;p&gt;For this example, we would be using AWS CDK as our IaC of choice.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Overall Process:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configure the infrastructure by creating a lambda function and an S3 bucket construct.&lt;/li&gt;
&lt;li&gt;Create an IAM policy statement for the said lambda function that has get and put access to the S3 bucket.&lt;/li&gt;
&lt;li&gt;Edit the lambda function handler where it returns a signed URL from the S3 bucket.&lt;/li&gt;
&lt;li&gt;Invoke the lambda function.&lt;/li&gt;
&lt;li&gt;Upload image using the signed URL (this is a PUT request) from the client.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First is to create an S3 bucket construct.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-s3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bucketID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bucket name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="na"&gt;publicReadAccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="na"&gt;allowedMethods&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt; &lt;span class="c1"&gt;// Allow methods&lt;/span&gt;
      &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HttpMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HttpMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HttpMethods&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;allowedOrigins&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// Just for the sake of local and dev development&lt;/span&gt;
    &lt;span class="na"&gt;allowedHeaders&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next is to create a lambda function construct. This lambda function returns a signed URL from Amazon S3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getsignedurl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODEJS_14_X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromAsset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path/to/function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function.handler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UploadBucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BUCKET_NAME&lt;/span&gt; &lt;span class="c1"&gt;// 'bucket name'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a Amazon S3 policy statement to be granted to the newly created lambda function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// s3Bucket Policy for profileImageUpload lambda function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3BucketPolicy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PolicyStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALLOW&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
  &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3:getObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3:putObjectAcl&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s3:putObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
  &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`arn:aws:s3:::&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/*`&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Added S3 policy to image upload lambda function&lt;/span&gt;
&lt;span class="nx"&gt;getsignedurl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;attachInlinePolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Policy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uploadPolicy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;s3BucketPolicy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, &lt;em&gt;&lt;strong&gt;don't forget to integrate the lambda function in its corresponding API gateway&lt;/strong&gt;&lt;/em&gt; to serve as a trigger!&lt;/p&gt;

&lt;p&gt;The code below will be the logic inside your newly created lambda function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;URL_EXPIRATION_SECONDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;profileImageUpload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;profileImageUpload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.jpg`&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3Params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UploadBucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     
      &lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      
      &lt;span class="na"&gt;Expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;URL_EXPIRATION_SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      
      &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image/jpeg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      
      &lt;span class="na"&gt;ACL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public-read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uploadURL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getSignedUrlPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;putObject&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s3Params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;uploadURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uploadURL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        
        &lt;span class="nx"&gt;Key&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;      
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;      
      &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The userID will serve as a unique key for the name of the object uploaded to the S3 bucket. This lambda function will return an upload URL and a Key. This upload URL will be used to send a PUT request with the request body having a binary file which is the picture or object to be uploaded.&lt;/p&gt;

&lt;p&gt;The example below is a Postman call of our newly created lambda function which returns an upload URL and a Key. The Key is part of the object URL in the cloud which makes it accessible if you stitch together your own bucket URL and Key!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mgPHXdQp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iushyj80jnbraw4vfd89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mgPHXdQp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iushyj80jnbraw4vfd89.png" alt="Postman Picture" width="826" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now call a PUT request to the returned upload URL and attach the picture in the request body. It shown in the example below. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o1adM9QZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aztujbi8qubwtfe66xe3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o1adM9QZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aztujbi8qubwtfe66xe3.png" alt="Postman Picture" width="821" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click send and go check your newly uploaded photo in the AWS console!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>aws</category>
      <category>cloud</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Debugging lambda functions with AWS CDK (using Webstorm)</title>
      <dc:creator>Ike Gabriel Yuson</dc:creator>
      <pubDate>Mon, 02 May 2022 12:01:41 +0000</pubDate>
      <link>https://dev.to/ikeman09/debugging-lambda-functions-with-aws-cdk-using-webstorm-3h06</link>
      <guid>https://dev.to/ikeman09/debugging-lambda-functions-with-aws-cdk-using-webstorm-3h06</guid>
      <description>&lt;h2&gt;
  
  
  PREREQUISITES
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install AWS CDK and AWS SAM (along with Docker)&lt;/li&gt;
&lt;li&gt;Install Webstorm &lt;/li&gt;
&lt;li&gt;Install AWS Toolkit Webstorm plugin&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  INTRODUCTION
&lt;/h2&gt;

&lt;p&gt;Step-debugging lambda functions in AWS CDK applications can be quite tricky since the invocation of lambda functions behave of that of a docker container.&lt;/p&gt;

&lt;p&gt;AWS SAM can be used to invoke/run your lambda functions locally with the following commands:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ sam local start api&lt;/code&gt;&lt;br&gt;
&lt;code&gt;$ sam local invoke&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Partnered by API clients (e.g Postman, Insomnia) and/or CLI tools to transfer data using various network protocols (e.g curl), local development can be quite robust with AWS CDK. &lt;/p&gt;

&lt;p&gt;However, step-debugging is not quite as seamless as locally invoking lambda functions with CDK. Through docker containers, &lt;strong&gt;&lt;em&gt;the behavior of invoking local lambda functions mimics that of a lambda function deployed in the cloud&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;In the cloud, lambda functions are ephemeral where execution environments only exist for a brief time when the function is invoked. This behavior is exactly the same with that of local development through docker containers. When a lambda is locally invoked, Docker builds an image that of the lambda function and runs the container. After the runtime of the lambda function, the container then stops and gets deleted. Can you see the parallelism with deployed lambda functions in the cloud? &lt;strong&gt;&lt;em&gt;Turns on when called and then goes back to sleep after execution&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When locally invoking a lambda function, &lt;strong&gt;&lt;em&gt;an API call with the use of an API client will only call the container that has successfully been built&lt;/em&gt;&lt;/strong&gt;. This is the reason why we cannot simply attach a debugger using our IDEs - a containerized application (in this case a lambda function) must be debugged inside the container as well. &lt;/p&gt;

&lt;p&gt;In order to debug the lambda function locally, &lt;strong&gt;&lt;em&gt;we must attach a debugger as soon as we invoked the lambda function&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;




&lt;h2&gt;
  
  
  WALKTHROUGH
&lt;/h2&gt;

&lt;p&gt;First we need to configure the AWS toolkit plugin by updating your AWS credentials.  You will be asked for your AWS ACCESS KEY ID and your AWS SECRET ACCESS KEY. After configuring your AWS credentials, go to Settings → Tools → AWS. Then select the drop down button of the AWS tab then select “Lambda”. Check the “Show gutter icons for all potential AWS Lambda handlers”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A6SCc-5A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5nvulimxgqjgwx8h9a5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A6SCc-5A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p5nvulimxgqjgwx8h9a5.png" alt="AWS Tookit Lambda option" width="880" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then go to your lambda function handler. You will now be able to see a lambda function logo in the gutter next to your handler.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---rbm4un6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/irhpd0vuq2mklamski4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---rbm4un6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/irhpd0vuq2mklamski4g.png" alt="Lambda function logo in the gutter" width="604" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the lambda function logo and select “Modify Run Configuration”. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i3MjLJ_l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnu1c6daxlr49n8tfxie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3MjLJ_l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnu1c6daxlr49n8tfxie.png" alt="Modify run configuration (AWS Toolkit)" width="753" height="564"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Fill-out the necessary information about your lambda function. The input portion is asking for an event that invokes the lambda function. This mimics the actual invocation of a lambda function from the cloud. The event that I used in this example is an API Gateway AWS Proxy where it invokes a lambda function through an API call from AWS API Gateway service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2NLh3i95--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8wiktmwuu8pro738uowj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2NLh3i95--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8wiktmwuu8pro738uowj.png" alt="events.json file" width="880" height="494"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is an example of an API Gateway AWS Proxy event. Looks daunting? Don’t worry! &lt;strong&gt;&lt;em&gt;AWS Toolkit provides you templates to use for specific events&lt;/em&gt;&lt;/strong&gt; located at the configuration settings of your lambda functions. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E3lyEYOb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e51ev5ssxk1vcavfrt7k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E3lyEYOb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e51ev5ssxk1vcavfrt7k.png" alt="Event Templates" width="753" height="552"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Click on the “-- Event Templates --” drop down and &lt;strong&gt;&lt;em&gt;AWS Toolkit will provide you with ALL the events that invokes lambda functions in AWS&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Moving forward, go to the SAM CLI tab and select “Build function inside a container”. This is the safest way to avoid NodeJS version errors. An example would be if you are using a different version of Node and the compatible runtimes of your lambda functions are different too. It’s best to containerize the debugging session to an isolated environment to avoid these types of errors. &lt;/p&gt;

&lt;p&gt;Apply all your changes and you are all set! &lt;strong&gt;&lt;em&gt;To debug your lambda function, setup some breakpoints and click the lambda function logo and run “Debug”!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  PROBLEMS
&lt;/h2&gt;

&lt;p&gt;The walkthrough above seems seamless and quite easy right? However, &lt;strong&gt;&lt;em&gt;lambda functions invoked from the handler does not take into account lambda layers&lt;/em&gt;&lt;/strong&gt;. You might ask why can’t we just select the “From template” option? But the thing is, &lt;strong&gt;&lt;em&gt;with CDK, there is no template.yaml file&lt;/em&gt;&lt;/strong&gt;. You might also suggest to convert the .template.json file to a template.yaml with the command: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ cdk synth --no-staging &amp;gt; template.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Yes, this converts the template.json file to a template.yaml however, the &lt;strong&gt;&lt;em&gt;template.yaml produced is NOT the same as the template.yaml of AWS SAM&lt;/em&gt;&lt;/strong&gt;. This then will lead to errors in compile time when AWS Toolkit runs:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ sam build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We also don’t want to create another template.yaml file with the correct AWS SAM format. This will just only mimic your current IaC (Infrastructure as Code) with CDK which may lead you to confusion in the future since editing infrastructure will lead you to change both AWS CDK’s stacks and AWS SAM’s template.yaml file. A problem may arise where you deployed your infrastructure through the AWS SAM CLI instead using AWS CDK. &lt;strong&gt;&lt;em&gt;Remember that SAM is a tool for CDK - not the other way around&lt;/em&gt;&lt;/strong&gt;. Also, DRY!! - Don’t Repeat Yourself.&lt;/p&gt;




&lt;h2&gt;
  
  
  WORKAROUND
&lt;/h2&gt;

&lt;p&gt;My workaround is to create a package.json file with all the dependencies inside the lambda functions folder. I know what you’re thinking, aren’t I repeating myself? Yes, I am but this is only for local development and great developer experience for us to use step-debugging in lambda functions with AWS CDK. If we were using AWS SAM this maybe quite easier for us but CDK is quite more robust when it comes to infrastructure. I consider it as the “true” IaC since we can also test the infrastructure with testing libraries such as Jest.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cxg9w9D8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/82jgtrf8d9hzt0c78cgl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cxg9w9D8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/82jgtrf8d9hzt0c78cgl.png" alt="File structure" width="303" height="254"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Install all the dependencies and don’t forget to put “node_modules”, “aws-toolkit-ts-output”, and “aws-toolkit-tsconfig.json” in the gitignore since these files were created when AWS Toolkit ran &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ sam build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you don’t want to use step-debugging, you can just simply invoke the API Gateway with the command &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ sam local start-api&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and call you’re API endpoints with an API Client such as Postman or Insomnia. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;As said above, after creating a package.json and install the needed dependencies, just setup some breakpoints in your lambda function and click the lambda function logo located at the gutter and run “Debug”!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>aws</category>
      <category>cloud</category>
      <category>serverless</category>
    </item>
    <item>
      <title>My Love Story With Tech</title>
      <dc:creator>Ike Gabriel Yuson</dc:creator>
      <pubDate>Mon, 31 Jan 2022 16:30:40 +0000</pubDate>
      <link>https://dev.to/ikeman09/my-love-story-with-tech-4eh1</link>
      <guid>https://dev.to/ikeman09/my-love-story-with-tech-4eh1</guid>
      <description>&lt;p&gt;My experience with tech wasn't exactly a bed of roses. It's more of a romantic relationship where there were ups and downs, misunderstandings, and euphoria. Tech can be very complex but is never incomprehensible.&lt;/p&gt;

&lt;p&gt;I am Ike Gabriel Yuson, currently a 2nd year student taking up a bachelor’s degree in Computer science at the University of the Philippines - Mindanao. I am also a freelance web developer who is also gunning for internships to add to my experience in the industry. Up until this point in my life, I only realized how big, beautiful, and challenging the tech industry is.&lt;/p&gt;

&lt;p&gt;Although it was not until high school when I was exposed to tech. During this time, I had my fair share of competitive programming competitions and various hackathons both on-site and online. It was where I discovered different fields in computer science.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: Butterflies
&lt;/h2&gt;

&lt;p&gt;People usually incorporate “love-at-first-sight” to a person but in 8th grade, I also had mine. With tech. This was the time I was introduced to programming and computer science. The exhilaration and the rush of adrenaline I experienced when writing my first &lt;code&gt;Hello World&lt;/code&gt; program in Java was on the roof! That day I realized I want to come across this feeling time and time again and until now, I still have the same intense addictive rush when solving problems in tech.&lt;/p&gt;

&lt;p&gt;All throughout high school, I was able to discover various fields in computer science such as web development, game development, and data science which made me love the industry even more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 2: Assimilation
&lt;/h2&gt;

&lt;p&gt;Upon going into college, I was already cognizant of what profession I was going to take - to work in the tech industry. A very broad ambition, right? During this time, there were only two things I was sure about - first is that I love programming, and second, I would be taking up a bachelor’s degree in computer science. Never really did I thought about what specialization I would want to take may it be web development, game development, and data science, etc. &lt;strong&gt;I was naïve for thinking that a college diploma was all I needed to jump start my career to be a successful computer scientist.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just around the 2nd semester of my 1st year in college, as I was coding data structures for a course requirement, a thought then hit me - &lt;em&gt;will I really be able to apply this in a professional corporate level?&lt;/em&gt; To be fair, I do appreciate the knowledge and logic imparted when studying data structures. Up until now, I practice coding them in HackerRank for I consider it as physical exercise for a programmer's brain and are even used as interview questions when applying for various tech jobs.&lt;/p&gt;

&lt;p&gt;However, as I was browsing different job opportunities in the industry, I then noticed that I never even got to learn all these "&lt;em&gt;alien&lt;/em&gt;" technologies in the job requirements section such as React, Nodejs, Django, etc. Never did I saw a job requirement indicating "Professional in implementing binary trees and graphs". Impostor syndrome struck and it was precisely at that moment that I considered myself clueless when it comes to the dirty work and technical skills required for a certain tech job.&lt;/p&gt;

&lt;p&gt;I then looked at my degree program curriculum and to my surprise, nothing indicated that I would be learning these technologies. I then realized that this was one of those up-to-date technologies that are not taught in my university. And so, I took matters into my own hands.&lt;/p&gt;

&lt;p&gt;I decided that I would want to learn web development first. Mainly because I see the web developer job at least 80% of the time when searching for job opportunities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 3: Building
&lt;/h2&gt;

&lt;p&gt;Learning React was my first goal in mind and this was &lt;strong&gt;the start of my insatiable hunger towards learning new things.&lt;/strong&gt; Up until that point, I was more of a go-with-the-flow type of guy. I just wait what my teachers and professors to tell the class what to study and do and I then follow. I never considered myself as self-taught up until now.&lt;/p&gt;

&lt;p&gt;The knowledge I had then for React was then enough to make my own personal website to be used for internship applications. I was fortunate enough to be accepted to a remote web development internship program overseas. This was where I learned about various architectures and technologies fit for full-stack development. Along with my peers, we made a single-page application that rewards loyal customers of small businesses. This was my first encounter with the MERN stack.&lt;/p&gt;

&lt;p&gt;During the first meeting with my mentor, I was extremely nervous to the point that I wanted to back-out from the program as he was spouting terms and technologies I haven't encountered and couldn't understand. Impostor syndrome struck once again, and my hands were basically shaking while I was typing my notes as he talks. After the technical talk, I then asked him if I could learn all these technologies in a short amount of time and the only advice he told me was to &lt;strong&gt;take it slow.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I then heed his advice and started to research and develop. First up was everything about the MERN stack - MongoDB, Express, React, and Nodejs. For months, I was never aware of the time. When I wake up in the morning, I immediately read articles and watch tutorial videos and at the same time code our MVP. I never noticed that I was already at it for 12-hours straight and next thing I knew it's already 3am in the morning.&lt;/p&gt;

&lt;p&gt;One thing led to another, and I already found myself studying about technologies irrelevant to the internship's tech stack! During this time, I always wondered how to publish a full web application on the internet so I was able to fiddle around with docker, switched from Windows to Linux (because why not? 😂), studied web servers like NGINX, and even read articles about AWS.&lt;/p&gt;

&lt;p&gt;When my mentor told me that we would be implementing a Serverless microservice architecture with AWS I was super excited upon hearing the news!&lt;/p&gt;

&lt;p&gt;This was the time I utterly fell in love with DevOps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 4: Stability
&lt;/h2&gt;

&lt;p&gt;My tech journey so far has been exhausting and hopefully far from over. Yes, it was quite tiresome and never was an easy ride however, I never thought about stopping. You see, I can be quite the persistent guy, and that’s what I’m doing with programming, too. May it be developing a web application or automating a certain job in CI/CD pipeline, I would never get tired of it!&lt;/p&gt;

&lt;p&gt;I realize that &lt;strong&gt;this industry will make you feel like you're a complete beginner every now and then.&lt;/strong&gt; Technology evolves at an exponential rate and who knows, the tech we have now would no longer be relevant a year or a couple of years later.&lt;/p&gt;

&lt;p&gt;Additionally, getting Linkedin messages for job opportunities makes me blush every time for these messages are actually a big deal for me considering that I am still an undergrad. This made me realize that &lt;strong&gt;there are more valid credentials than that of a college diploma.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Having experienced full-stack development granted me a taste of what I decided to be my profession for the rest of my life. Although dealing with impostor syndrome every now and then can be a pain in the ass, but reliving how clueless I was before and assessing how far I have come somewhat does the trick. &lt;strong&gt;My curiosity led me to where I am now.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As of writing, I have now made a carpool tracker web application that follows a serverfull microservice architecture. This was when I got to be hands-on with docker and other Amazon web services such as ECS, EKS, and ECR. I am currently working on an ElectronJS project and studying container orchestration with Kubernetes.&lt;/p&gt;

&lt;p&gt;Upskilling as early as now has been one of the best decisions of my life and I can't wait to learn new things in the future!&lt;/p&gt;

</description>
      <category>career</category>
      <category>beginners</category>
      <category>motivation</category>
    </item>
  </channel>
</rss>
