<?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: Frangeris Peguero</title>
    <description>The latest articles on DEV Community by Frangeris Peguero (@frangeris).</description>
    <link>https://dev.to/frangeris</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%2F950757%2F19bb771c-609b-4daa-ab0b-992c01921c6b.jpeg</url>
      <title>DEV Community: Frangeris Peguero</title>
      <link>https://dev.to/frangeris</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/frangeris"/>
    <language>en</language>
    <item>
      <title>Stale cache, the holy grail of performance</title>
      <dc:creator>Frangeris Peguero</dc:creator>
      <pubDate>Tue, 29 Oct 2024 21:09:13 +0000</pubDate>
      <link>https://dev.to/cloudx/stale-cache-the-holy-grail-of-performance-29be</link>
      <guid>https://dev.to/cloudx/stale-cache-the-holy-grail-of-performance-29be</guid>
      <description>&lt;p&gt;Cache on APIs is a must-have feature for any service that aims to scale. It's a way to reduce the load on your servers and improve the response time for your users by serving the same content multiple times, getting the same result without having to process the request again.&lt;/p&gt;

&lt;p&gt;The issue is that... implementing cache systems is hard, tricky and can cause a lot of headaches when it comes to invalidating the cache, purging and keeping the cache fresh with the latest data.&lt;/p&gt;

&lt;p&gt;In this article we will explore the concept of stale cache, test different scenarios with examples and see how CDN providers like &lt;em&gt;Bunny CDN&lt;/em&gt; can help us to keep the cache fresh without having to purge it with every new request.&lt;/p&gt;




&lt;p&gt;Let's start by breaking down the pieces.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⌛️ Response time
&lt;/h2&gt;

&lt;p&gt;When you make a request to an API, the response time is what it takes for the server to process the request and send a response back.&lt;/p&gt;

&lt;p&gt;This time period can typically vary depending on multiple factors from its composition like the server's load, the network latency and the complexity of the request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Network latency&lt;/strong&gt;: the time it takes for the request to travel from the client to the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DNS lookup time&lt;/strong&gt;: what it takes for the client to resolve the server's domain name to an IP address.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connections and SSL Handshakes&lt;/strong&gt;: a set of ticks and checks that the server needs to do before sending the response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And when the requests finally arrive, then in the server side we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Processing time&lt;/strong&gt;: what it takes for the server to process the request and send back the response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Response size&lt;/strong&gt;: this affects the time it takes to transfer the data over the network.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As the processing time in the server is something we can control by optimizing the code, the other factors are out of our control. Despite that we can reduce the time it takes to process the request by using a cache system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are others factors like "cold-start" time on serverless implementations that also increase the time it takes to process the request, but this is out of the scope of this article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Now, how the cache system works?
&lt;/h2&gt;

&lt;p&gt;A client requests information to a server, the server processes the request and sends back the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages#body" rel="noopener noreferrer"&gt;response body&lt;/a&gt;, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status" rel="noopener noreferrer"&gt;http status code&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Response_header" rel="noopener noreferrer"&gt;headers&lt;/a&gt;. Two of these headers are key to understand how the cache system works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache-Control&lt;/strong&gt;: Dictates the mechanism to control for &lt;em&gt;whom&lt;/em&gt;, &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;until when&lt;/em&gt; the response can be cached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ETag&lt;/strong&gt;: Is a unique identifier for the response state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Currently, the &lt;a href="https://www.rfc-editor.org/rfc/rfc7540" rel="noopener noreferrer"&gt;HTTP/2 RFC Specification&lt;/a&gt; defines how the &lt;code&gt;Cache-Control&lt;/code&gt; header should work telling the client (or intermediary caches like CDNs) how to behave. It also inherits the same directives from the HTTP/1.1 specification with some extra improvements.&lt;/p&gt;

&lt;p&gt;In the other hand, the &lt;code&gt;ETag&lt;/code&gt; is used like an index key: if the value hasn't change, the cache can be used; if not, a new fresh response is needed. It solves the problem of seeing if the data has changed or not, but it can't solve the problem of keeping the cache fresh with the latest data. This is where the concept of &lt;em&gt;stale cache&lt;/em&gt; comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stale cache
&lt;/h2&gt;

&lt;p&gt;By working with this concept the cache is served by an intermediary to the client even if it's expired while the server is still processing the request in the background to get the latest data. When the server gets the latest data, it updates the cache with the new data and serves it fresh to the client on the next request.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Cache-Control&lt;/code&gt; header can be extended with the functionality described above. This is done via the directive &lt;code&gt;stale-while-revalidate&lt;/code&gt; that tells the client (or intermediary) to &lt;em&gt;serve the stale cache while revalidate&lt;/em&gt; in the background.&lt;/p&gt;

&lt;p&gt;The directive can receive a value in seconds. This value is the time during the &lt;em&gt;stale&lt;/em&gt; cache can be served while the server is processing the request to get the latest data; for instance, a header with this directive can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cache-Control: max-age=604800, stale-while-revalidate=86400
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Which translates to: "serve the cache for 7 days, but if the cache is expired then serve the stale cache for 1 day while the server is processing the request to get the latest data".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This level of customization is then used by CDNs to keep the cache fresh without having to purge it every time a new request is made. It basically always returns the cache but, when a new version is available, it updates the cache and serves that new version to any new request. Simply like magic.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔒 &lt;code&gt;private&lt;/code&gt; / &lt;code&gt;public&lt;/code&gt; directives
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Cache-Control&lt;/code&gt; header can also support "some kind" of privacy level. The difference between having those values is that the &lt;code&gt;public&lt;/code&gt; value will be interpreted as if they were allowed to store the response in a shared cache, while the &lt;code&gt;private&lt;/code&gt; one is intended to be stored only in the client's (local caches or browsers).&lt;/p&gt;

&lt;p&gt;Basically the &lt;code&gt;public&lt;/code&gt; directive is used when the response is the same for all users, while the &lt;code&gt;private&lt;/code&gt; directive is used when the response doesn't need to be saved as cache by a CDN.&lt;/p&gt;

&lt;p&gt;Having understood the concept of stale cache, let's see how we can implement this on a real-world scenario.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡️ Some testings
&lt;/h2&gt;

&lt;p&gt;Let's test this concept with a simple API that returns a random number that will be deployed on &lt;code&gt;us-east-2&lt;/code&gt; zone on AWS API Gateway.&lt;/p&gt;

&lt;p&gt;Making a GET request to the endpoint &lt;code&gt;/random&lt;/code&gt; will return a random number between 1 and 100 due to the cold-start time of serverless functions. The first request will take a little longer to respond, but the next requests will be faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fui7hdbyb92p2gzhf6h6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fui7hdbyb92p2gzhf6h6f.png" alt="Response time of first request" width="523" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This example shows some of the factors explained at the beginning of the article, subsequent requests can take between &lt;code&gt;200ms&lt;/code&gt; and &lt;code&gt;450ms&lt;/code&gt; of response time depending of the lambda invoke response, even with some of tracing being cached like &lt;em&gt;DNS Lookup, TCP Handshake, SSL Handshake&lt;/em&gt;, this is pretty normal as the origin of the request is from South America and edge locations are not configured.&lt;/p&gt;

&lt;p&gt;So, how can we improve this response time? Let's add a cache system to the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's introduce bunny.net 🐇
&lt;/h2&gt;

&lt;p&gt;Bunny is a global content delivery platform that help us to delivers cached content faster. In this example, we will use Bunny to cache the responses of the API, see how the cache system works and how the stale cache can be implemented. They have a lot of features and capabilities, but for this example we will focus on CDN.&lt;/p&gt;

&lt;p&gt;With an account already created, we can create a new "pull zone". This is the layer that sits in front of the API and act as intermediary caching everything being requested. Given the name &lt;code&gt;xxxxxxx.b-cdn.net&lt;/code&gt; a domain will be created and we also need to add the "Origin URL" that is the api endpoint we want to cache.&lt;/p&gt;

&lt;p&gt;While creating the pull zone, they provide the options to check "in what zones" we want to store the cached data, so the content is served from the closest region instead of traveling all the way to the origin. We will select all the zones available so the cache is everywhere 🤯.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ws1jyzsgemem6oy8gnt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ws1jyzsgemem6oy8gnt.png" alt="Pull zone for edge locations" width="691" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the pull zone created, is ready to be used as proxy for the API. Now let's move back the the endpoint code to make the header customization so bunny know what to do with our origin responses.&lt;/p&gt;

&lt;p&gt;We can start making requests to the new domain pull zone domain, so anything requested to the CDN will be forwarded behind scenes to API but caching the response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// instead of
GET https://api.example.com/random

// use the pull zone domain
GET https://mynewpullzone.b-cdn.net/random
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default our cache control header is set to &lt;code&gt;no-cache&lt;/code&gt;, so every time we hit the pull zone URL provided it will make a request to the origin, so lets change that behavior by just adding &lt;code&gt;max-age&lt;/code&gt; directive to the header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Cache-Control": `public, max-age=86400`,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will tell the CDN to cache the response for 1 day, so the next requests will be served from the cache instead of making a request to the origin. And by enabling the previous regions zones, the request will be served from the closest edge location to the client getting a lightning fast response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmk3esco03jrikd92bbj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmk3esco03jrikd92bbj.png" alt="Pull zone for edge locations" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔥 &lt;code&gt;18ms&lt;/code&gt; of response time, that's a huge improvement from the previous &lt;code&gt;200ms - 450ms&lt;/code&gt;, and this is just the beginning.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CDN-Cache&lt;/code&gt; header returned in the request tell us if the request was served by the CDN cache or not, in case the value is &lt;code&gt;MISS&lt;/code&gt;, the request was made to the origin, if the value is &lt;code&gt;HIT&lt;/code&gt;, the request was served from the cache.&lt;/p&gt;

&lt;p&gt;There are other features that can be implemented. Bunny provide features like "Query String Sorting" that, when enabled the query parameters will be automatically sorted into a consistent order before checking the cache. For example, this will treat &lt;code&gt;/random?width=200&amp;amp;height=100&lt;/code&gt; and &lt;code&gt;/random?height=100&amp;amp;width=200&lt;/code&gt; as the same path.&lt;/p&gt;

&lt;p&gt;But, there is still something missing. With this implementation the cached response will need to be updated when the expiration time is reached so the stale cache can be used, but even after the revalidate time is expired the CDN will hit a request to the origin to update the cache. This is not the best approach, so let's see how we can improve this.&lt;/p&gt;

&lt;p&gt;Bunny supports an option that can be enabled from the dash panel inside the pull zone cache options: the "Stale Cache", which basically "allows you to temporarily serve stale files from the CDN cache, while updating resources in the background". We have two available options here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;While Origin Offline&lt;/strong&gt;: Which will serve the stale cache while the origin is offline and down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;While Updating&lt;/strong&gt;: The one we are interested in, this will serve the stale cache and behind scenes update the cache with the latest data, so we always get the fresh data blazing fast thanks to their edge locations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wrapping up
&lt;/h3&gt;

&lt;p&gt;Implementing a cache system is crucial for improving the performance and scalability of your API services. By leveraging the concept of stale cache and using CDNs like Bunny.net, you can significantly reduce response times and server load. The &lt;code&gt;Cache-Control&lt;/code&gt; header, with directives like &lt;code&gt;stale-while-revalidate&lt;/code&gt;, allows you to serve stale content while fetching fresh data in the background, ensuring that your users always get the best possible experience. Remember, while Bunny.net is used in this example, these caching principles can be applied with any CDN provider that supports similar capabilities.&lt;/p&gt;

&lt;p&gt;Happy caching! 🍻&lt;/p&gt;

</description>
      <category>cache</category>
      <category>cdn</category>
      <category>api</category>
      <category>performance</category>
    </item>
    <item>
      <title>Upgradeable smart contracts</title>
      <dc:creator>Frangeris Peguero</dc:creator>
      <pubDate>Mon, 31 Jul 2023 15:09:19 +0000</pubDate>
      <link>https://dev.to/cloudx/upgradeable-smart-contracts-29d9</link>
      <guid>https://dev.to/cloudx/upgradeable-smart-contracts-29d9</guid>
      <description>&lt;h2&gt;
  
  
  The basis
&lt;/h2&gt;

&lt;p&gt;This series assumes you have a basic understanding of the smart contracts development and the Ethereum or EVM compatible blockchains and that you also have a local development setup already working. If you are not familiar with these topics, please read the &lt;a href="https://ethereum.org/en/smart-contracts/" rel="noopener noreferrer"&gt;Introduction to smart contracts&lt;/a&gt; to start.&lt;/p&gt;

&lt;p&gt;One of the most popular implementations of smart contracts today is the &lt;a href="https://eips.ethereum.org/EIPS/eip-20" rel="noopener noreferrer"&gt;ERC20&lt;/a&gt; token standard. It is a set of rules that defines how a token contract should behave. It is a standard that allows different applications to interact with the token knowing how it works. For example, a wallet application can display the balance of a token, or a decentralized exchange can trade it. The standard creates and endless possibilities of functionalities that can be built on top of it.&lt;/p&gt;

&lt;p&gt;We are going to focus in creating a &lt;a href="https://en.wikipedia.org/wiki/Payment_gateway" rel="noopener noreferrer"&gt;payments gateway&lt;/a&gt; by using the ERC20 standard as the basis for our tokens. This will allow us to share the implementation with other applications that support the standard interface as the popular stable coins: &lt;a href="https://www.circle.com/en/usdc" rel="noopener noreferrer"&gt;USDC&lt;/a&gt;, &lt;a href="https://tether.to/en/" rel="noopener noreferrer"&gt;USDT&lt;/a&gt;, &lt;a href="https://makerdao.com/en/" rel="noopener noreferrer"&gt;DAI&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;"The immutable problem"&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The pure concept of smart contracts is that they are immutable. Once a contract is deployed, it cannot be changed. This is a great feature because it allows us to trust the code that is running in the blockchain. We can be sure that the code will not change and that it will behave as expected. This means that if we want to add new features or fix something broken inside the contracts, we need to deploy a new contract and migrate the state to the new one; this is not a problem for a new contract, but it is a big problem for an existing one with a lot of users interacting with it.&lt;/p&gt;

&lt;p&gt;That's why the concept of "upgradeable contracts" was created. The idea is to have a contract that can be upgraded without losing the state. This is a very complex topic and there are many different approaches to it. We are going to use the &lt;a href="https://docs.openzeppelin.com/upgrades-plugins/1.x/" rel="noopener noreferrer"&gt;OpenZeppelin Upgrades&lt;/a&gt; library to create our upgradeable contracts.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How the proxy pattern works?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The secret behinds a proxy consists in a contract that provides a fallback function that delegates all calls to another contract using the EVM instruction &lt;code&gt;delegatecall&lt;/code&gt;, which is a low-level function that allows calling another contract using the current contract &lt;strong&gt;storage&lt;/strong&gt; and &lt;strong&gt;context&lt;/strong&gt;. This means that the contract being called can access the storage of the contract that is calling it. This is the key to the proxy pattern.&lt;/p&gt;

&lt;p&gt;Here is an example of how &lt;code&gt;delegatecall&lt;/code&gt; works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// NOTE: Deploy this contract first
contract B {
    // NOTE: storage layout must be the same as contract A
    uint public num;
    address public sender;
    uint public value;

    function setVars(uint _num) public payable {
        num = _num;
        sender = msg.sender;
        value = msg.value;
    }
}

contract A {
    uint public num;
    address public sender;
    uint public value;

    function setVars(address _contract, uint _num) public payable {
        // A's storage is update, B state is not modified.
        (bool success, bytes memory data) = _contract.delegatecall(
            abi.encodeWithSignature("setVars(uint256)", _num)
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short words, the proxy contract is the one that DApps interact with while using the logic of other contract in the proxy context. This means that the proxy contract will be the one that is deployed and the one that users will interact with, while the logic contract will be the one that is upgraded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F04.image.1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F04.image.1.png" alt="Meme about how proxy is behind scenes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More technical documentation can be found on the &lt;a href="https://docs.soliditylang.org/en/v0.8.20/introduction-to-smart-contracts.html#delegatecall-and-libraries" rel="noopener noreferrer"&gt;Solidity docs&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When working with upgradeable contracts using OpenZeppelin Upgrades, there are a few minor caveats to keep in mind when writing your Solidity code.&lt;/p&gt;

&lt;p&gt;It’s worth mentioning that these restrictions have their roots in how the Ethereum VM works, and apply to all projects that work with upgradeable contracts, not just OpenZeppelin Upgrades.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some of the caveats of using the proxy pattern are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Initializers: Contructors are not allowed in upgradeable contracts and we need to use the &lt;code&gt;initialize&lt;/code&gt; function from the &lt;code&gt;Initializable&lt;/code&gt; contract instead. This function is called only once when the contract is deployed for the first time. This means that we need to use the &lt;code&gt;initializer&lt;/code&gt; modifier inside the &lt;code&gt;initialize&lt;/code&gt; function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extending from upgradeable contracts libraries: Following the same logic, we need to use the &lt;code&gt;initializer&lt;/code&gt; modifier when extending from upgradeable contract libraries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initial values and fields declarations: We need to be careful when declaring fields in our contracts, because the initial values are not set when the contract is deployed. This means that we need to set the initial values in the &lt;code&gt;initialize&lt;/code&gt; function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Initialization of implemented contracts: As constructors are disabled when working with upgradeability, while extending from a contract, we call the function that "initialize" instead of calling the parent via &lt;code&gt;super&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not &lt;code&gt;selfdestruct&lt;/code&gt; or &lt;code&gt;delegatecall&lt;/code&gt; implemented: These functions are not supported in upgradeable contracts to avoid breaking the proxy pattern or opening a door to security issues.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;More detailed information can be found in the &lt;a href="https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable" rel="noopener noreferrer"&gt;OpenZeppelin Upgrades documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The implementation
&lt;/h2&gt;

&lt;p&gt;To give the ability of upgradeability to our "Gateway" (in case something goes wrong or needs to be changed), we need to use the proxy pattern. So let's start by creating and deploying a &lt;code&gt;Gateway.sol&lt;/code&gt; contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract Gateway is Initializable, OwnableUpgradeable {
  uint private fee;

  function initialize(uint _fee) public initializer {
    fee = _fee;
    __Ownable_init();
  }

  function getFee() public view returns (uint) {
    return fee;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This contract is very simple, it has a &lt;code&gt;fee&lt;/code&gt; variable that can be set by the owner of the contract. This is the contract that we are going to be upgrading.&lt;/p&gt;

&lt;p&gt;To deploy it we need to use the &lt;code&gt;deployProxy&lt;/code&gt; function from the &lt;code&gt;@openzeppelin/hardhat-upgrades&lt;/code&gt; plugin. This function will deploy the proxy contract and initialize it with the &lt;code&gt;initialize&lt;/code&gt; function from the &lt;code&gt;Gateway&lt;/code&gt; contract.&lt;/p&gt;

&lt;p&gt;To keep things simple and visible (in case you cant deploy), we will use &lt;a href="https://sepolia.dev/" rel="noopener noreferrer"&gt;Sepolia testnet&lt;/a&gt; blockchain and &lt;a href="https://hardhat.org/" rel="noopener noreferrer"&gt;Hardhat&lt;/a&gt; as development environment, so to configure hardhat to use sepolia we need to add the following configuration to the &lt;code&gt;hardhat.config.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;networks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;sepolia&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://rpc.sepolia.org/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

      &lt;span class="c1"&gt;// private key of the account that will deploy the contracts (owner)&lt;/span&gt;
      &lt;span class="na"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;:&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;ACCOUNT_PRIVATE_KEY&lt;/span&gt;&lt;span class="o"&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;Then we can tell Hardhat to run the deployment script while specifying the network to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hardhat run scripts/deploy.js &lt;span class="nt"&gt;--network&lt;/span&gt; sepolia
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F04.image.2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F04.image.2.png" alt="Output of deploy script"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should be able to see the same transaction on &lt;a href="https://sepolia.etherscan.io/address/0x10Ccb5C22C6Ccc78F6B5dfbCB36Ea13bF60d2Ecf" rel="noopener noreferrer"&gt;Sepolia Block Explorer&lt;/a&gt;. Now let's take a look at the transactions details (lookup your wallet address in etherscan), &lt;code&gt;3&lt;/code&gt; contracts were created:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;TransparentUpgradeableProxy&lt;/code&gt;: This is the proxy contract that will be used to interact with the Gateway contract, &lt;a href="https://sepolia.etherscan.io/address/0xe7197e1d5f60ee3745a828a4ceadaa0fbfff886d#code" rel="noopener noreferrer"&gt;see it here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProxyAdmin&lt;/code&gt;: This contract is used to manage the proxy contracts (admin / upgrades), &lt;a href="https://sepolia.etherscan.io/address/0xe754bdb16e0fc27d5d405432c523099c2c9050b2#code" rel="noopener noreferrer"&gt;see it here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Gateway&lt;/code&gt;: This is the logic contract that will be used by &lt;code&gt;TransparentUpgradeableProxy&lt;/code&gt;, &lt;a href="https://sepolia.etherscan.io/address/0x739af28dfecd11067f5be66f56f3fb37403c496f#code" rel="noopener noreferrer"&gt;see it here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that Gateway contract code is not available as the others: only the bytecode is shown. This is because it was deployed by the proxy; to be able to see the real code you can verify and publish it via hardhat.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Any future interaction with the &lt;code&gt;Gateway&lt;/code&gt; contract will be done via the &lt;code&gt;TransparentUpgradeableProxy&lt;/code&gt; contract, so let's try to interact with it. To do so, let's use &lt;code&gt;hardhat console&lt;/code&gt; to interact with the blockchain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx hardhat console &lt;span class="nt"&gt;--network&lt;/span&gt; sepolia
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why specify the network? Because we need to tell Hardhat which network to use to interact with the blockchain. In this case we are using the &lt;code&gt;sepolia&lt;/code&gt; network and we will also use &lt;code&gt;ethersjs&lt;/code&gt; to interact with the deployed contract.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;frang @ ~/Code/posts-examples/payments-gateway &lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt;
 →  npx hardhat console &lt;span class="nt"&gt;--network&lt;/span&gt; sepolia
Welcome to Node.js v14.18.1.
Type &lt;span class="s2"&gt;".help"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more information.
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; const proxy &lt;span class="o"&gt;=&lt;/span&gt; await ethers.getContractFactory&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Gateway"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
undefined
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; const gateway &lt;span class="o"&gt;=&lt;/span&gt; await proxy.attach&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"0xe7197e1D5F60eE3745a828a4CeaDAA0FBfFF886D"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
undefined
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;await gateway.getFee&lt;span class="o"&gt;())&lt;/span&gt;.toString&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="s1"&gt;'1'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we are able to interact with the &lt;code&gt;Gateway&lt;/code&gt; contract via the &lt;code&gt;TransparentUpgradeableProxy&lt;/code&gt; contract, but what if we want to upgrade the &lt;code&gt;Gateway&lt;/code&gt; contract? Let's add support to allow the owner to change the fee by creating &lt;code&gt;GatewayV2.sol&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract GatewayV2 is Initializable, OwnableUpgradeable {
    uint private fee;

    function initialize(uint _fee) public initializer {
        fee = _fee;
        __Ownable_init();
    }

    function getFee() public view returns (uint) {
        return fee;
    }

    function setFee(uint _fee) public onlyOwner {
        fee = _fee;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new contract should be exactly the same as the previous one, but with the addition of the &lt;code&gt;setFee&lt;/code&gt; function, now let's deploy it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The difference between &lt;code&gt;upgrade&lt;/code&gt; script and the previous one is that we are using the &lt;code&gt;upgradeProxy&lt;/code&gt; function instead of &lt;code&gt;deployProxy&lt;/code&gt;, this function will upgrade the &lt;code&gt;Gateway&lt;/code&gt; contract to the new &lt;code&gt;GatewayV2&lt;/code&gt; contract.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;frang @ ~/Code/posts-examples/payments-gateway &lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt;
 →  &lt;span class="nv"&gt;PROXY_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0xe7197e1D5F60eE3745a828a4CeaDAA0FBfFF886D npx hardhat run scripts/upgrade.js &lt;span class="nt"&gt;--network&lt;/span&gt; sepolia
Upgrading...
Upgraded: 0xe7197e1D5F60eE3745a828a4CeaDAA0FBfFF886D
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract was upgraded, but how can we verify that? Let's try to interact with the contract again BUT this time we will use the &lt;code&gt;GatewayV2&lt;/code&gt; contract instead of the &lt;code&gt;Gateway&lt;/code&gt; contract while using the same contract address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;frang @ ~/Code/posts-examples/payments-gateway &lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt;
 →  npx hardhat console &lt;span class="nt"&gt;--network&lt;/span&gt; sepolia
Welcome to Node.js v14.18.1.
Type &lt;span class="s2"&gt;".help"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;more information.
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; const proxy &lt;span class="o"&gt;=&lt;/span&gt; await ethers.getContractFactory&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"GatewayV2"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
undefined
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; const gateway &lt;span class="o"&gt;=&lt;/span&gt; await proxy.attach&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"0xe7197e1D5F60eE3745a828a4CeaDAA0FBfFF886D"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
undefined
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;await gateway.getFee&lt;span class="o"&gt;())&lt;/span&gt;.toString&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="s1"&gt;'1'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; await gateway.setFee&lt;span class="o"&gt;([&lt;/span&gt;2]&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;hash&lt;/span&gt;: &lt;span class="s1"&gt;'0x699ad32e17ca56537d69c60ff4727526f031f53ca46775dad535d37300055cda'&lt;/span&gt;,
  ...
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;await gateway.getFee&lt;span class="o"&gt;())&lt;/span&gt;.toString&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="s1"&gt;'2'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contract now has the &lt;code&gt;setFee&lt;/code&gt; function, so we can change the fee, but how can we truly verify that the contract was upgraded? Every transaction is written in the blockchain, taking a look at the transaction details on &lt;a href="https://sepolia.etherscan.io/tx/0xc0ea9e236e0aea3534bd060fd081468c39649d0fb00cb44b19e241c85338757b#eventlog" rel="noopener noreferrer"&gt;Sepolia Block Explorer&lt;/a&gt;, you should be able to see the &lt;code&gt;Upgraded&lt;/code&gt; event. This event is emitted when the &lt;code&gt;Gateway&lt;/code&gt; contract was upgraded to the &lt;code&gt;GatewayV2&lt;/code&gt; contract.&lt;/p&gt;

&lt;p&gt;And that's it, we have the first contract for the payments gateway that can be upgraded, but what if we want to add more features to the contract? We can do that by creating a new contract that have the same interface as previous contracts, then just add the new features, deploy it and upgrade the proxy contract to the new contract; this way we can add new features without breaking the existing ones.&lt;br&gt;
With the upgradeable part covered, let's move to the next part.&lt;/p&gt;

</description>
      <category>ethereum</category>
      <category>solidity</category>
      <category>openzeppelin</category>
      <category>payments</category>
    </item>
    <item>
      <title>Ensuring secure values by private keys in AWS (KMS, SSM, Secrets Manager)</title>
      <dc:creator>Frangeris Peguero</dc:creator>
      <pubDate>Wed, 19 Apr 2023 15:10:26 +0000</pubDate>
      <link>https://dev.to/cloudx/ensuring-secure-values-by-private-keys-in-aws-kms-ssm-secrets-manager-2lmn</link>
      <guid>https://dev.to/cloudx/ensuring-secure-values-by-private-keys-in-aws-kms-ssm-secrets-manager-2lmn</guid>
      <description>&lt;h2&gt;
  
  
  Ensuring secure values by private keys in AWS (KMS, SSM, Secrets Manager)
&lt;/h2&gt;

&lt;p&gt;Private keys, access credentials, and sensitive information such as passwords or any kind of confidential data are essential in application's logic when interacting with other services or even databases. Storing those values can be risky if proper security measures are not in place.&lt;/p&gt;

&lt;p&gt;In this post we will dig into one way to accomplish secure access to sensitive information in AWS environments. For simplicity we will be using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A ready to use &lt;a href="https://aws.amazon.com" rel="noopener noreferrer"&gt;AWS account&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.serverless.com/framework/docs/getting-started" rel="noopener noreferrer"&gt;Serverless Framework&lt;/a&gt; - to delegate the CloudFormation creation and deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;This implementation focuses on the use of specifics services and functionalities provided by AWS services. Implementations will vary depending on the provider (Azure, GCP).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Let's start by creating a basic &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This function will try to access our "secure" and use it. By using &lt;code&gt;npx&lt;/code&gt; command we get access to serverless executable. I recommend you select the basic settings to keep it simple, but don't forget there are options for different types of uses cases, even different languages options in case &lt;code&gt;Node.js&lt;/code&gt; is not your language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F03.image.1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F03.image.1.png" alt="Run npx serverless command to start"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some operations used on the lambda function will require some permissions later. Due to this, it's recommended to include and enable those permissions before the IAM role of the lambda gets created. Here are the permissions we need the lambda to have:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="na"&gt;iam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;statements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
          &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:*"&lt;/span&gt;
          &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
          &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cloudwatch:*"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;logs:*"&lt;/span&gt;
          &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
          &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ssm:GetParameter"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ssm:GetParametersByPath"&lt;/span&gt;
          &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
          &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secretsmanager:GetSecretValue"&lt;/span&gt;
          &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
          &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:Decrypt"&lt;/span&gt;
          &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Then, with your &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html" rel="noopener noreferrer"&gt;aws account&lt;/a&gt; already set up, let's deploy it.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx sls deploy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;🎉 After a correct deployment, the code should have been created successfully and be ready to use. Now we need to configure the most important part: &lt;strong&gt;security&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Permissions will be managed via &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html" rel="noopener noreferrer"&gt;IAM policies&lt;/a&gt; with the objective of &lt;em&gt;only allow the lambda to get and decrypt the secured value&lt;/em&gt;. Plus, the approach used will be based on: &lt;strong&gt;prevent IAM entities from accessing the KMS key and allow the root user account to manage it&lt;/strong&gt; (also preventing the root user account from losing access to the KMS key).&lt;/p&gt;

&lt;p&gt;This "protection" layer of our sensitive value is based on the composition of two AWS services: &lt;a href="https://aws.amazon.com/kms/" rel="noopener noreferrer"&gt;Key Management Service&lt;/a&gt; is the one responsible for creating the private key which will be used to encrypt our value, then &lt;a href="https://aws.amazon.com/es/secrets-manager/" rel="noopener noreferrer"&gt;Secret Manager&lt;/a&gt; or &lt;a href="https://aws.amazon.com/systems-manager/" rel="noopener noreferrer"&gt;System Manager: Parameters Store&lt;/a&gt; allow us to accomplish the same functionality but they differ on some caveats, since &lt;em&gt;the chosen one&lt;/em&gt; will be used for saving the secured encrypted value. Here is a quick graphic representation of the implementation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F03.image.2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F03.image.2.png" alt="A diagram that explains how services are used"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now lets translate these concepts into code. The first thing we need after having the lambda functional and usable is to create the key used to encrypt our &lt;em&gt;precious value&lt;/em&gt;...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F03.image.3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F03.image.3.png" alt="Meme of our precious value"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So lets create the key using the "root" account and give it access to lambda just for &lt;code&gt;"kms:Decrypt"&lt;/code&gt;, not other operations!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please notice how we control and specify that only a specific ARN can call this value by: &lt;code&gt;kms:CallerArn: !Sub arn:aws:lambda:region:${AWS::AccountId}:function:myfunction&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;MyPrivateKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::KMS::Key&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;KMS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;private&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;key"&lt;/span&gt;
        &lt;span class="na"&gt;KeyUsage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENCRYPT_DECRYPT&lt;/span&gt;
        &lt;span class="na"&gt;KeyPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
          &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-key-1"&lt;/span&gt;
          &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Sid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enable&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;root&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;permissions"&lt;/span&gt;
              &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
              &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;AWS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::${AWS::AccountId}:root&lt;/span&gt;
              &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:*"&lt;/span&gt;
              &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Sid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;use&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;key"&lt;/span&gt;
              &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
              &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lambda.amazonaws.com&lt;/span&gt;
              &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kms:Decrypt"&lt;/span&gt;
              &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s"&gt;arn:aws:kms:region:${AWS::AccountId}:key/my-key-1&lt;/span&gt;
              &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;StringEquals&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;kms:CallerArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Sub&lt;/span&gt; &lt;span class="s"&gt;arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:myfunction&lt;/span&gt;
    &lt;span class="na"&gt;MyPrivateKeyAlias&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::KMS::Alias"&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;AliasName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alias/myprivatekey&lt;/span&gt;
        &lt;span class="na"&gt;TargetKeyId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;MyPrivateKey&lt;/span&gt;
  &lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# we will need this value later&lt;/span&gt;
    &lt;span class="na"&gt;MyKeyId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;MyPrivateKey&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;The ID of the KMS key used to encrypt&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;In this stage you should be able to have the lambda function and a secret key which both the root user and the lambda ARN can access and use it. Now, how about creating our encrypted values?&lt;/p&gt;

&lt;p&gt;For simplicity I personally prefer &lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; to handle the process of encrypting and saving instead of creating another lambda script that would need to use &lt;a href="https://aws.amazon.com/sdk-for-javascript/" rel="noopener noreferrer"&gt;AWS SDK&lt;/a&gt;, ending in the same result 🤷🏽&lt;/p&gt;

&lt;p&gt;So first, we need to encrypt our secret using the previous key already created, so that even if someone is able to access the value, they will need our key to be able to see the content,&lt;/p&gt;

&lt;p&gt;Some of the values used below are not exposed in the serverless deploy output, so those values are gotten via the &lt;em&gt;stack output&lt;/em&gt; previously defined as part of &lt;code&gt;serverless.yml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx sls info &lt;span class="nt"&gt;--verbose&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;--plaintext (data to be encrypted) is required to be base64 text or a blob from a plain text file&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws kms encrypt &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;same region used by serverless&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--key-id&lt;/span&gt; &amp;lt;key &lt;span class="nb"&gt;id &lt;/span&gt;from output &lt;span class="o"&gt;(&lt;/span&gt;MyPrivateKeyId&lt;span class="o"&gt;)&amp;gt;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--plaintext&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;base64 of value&amp;gt; or &amp;lt;fileb://path&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--output&lt;/span&gt; text &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--query&lt;/span&gt; CiphertextBlob


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;🎉 You should be able to get a base64 output from the command above with the encrypted value, now what next?&lt;/p&gt;
&lt;h3&gt;
  
  
  Store the values
&lt;/h3&gt;

&lt;p&gt;We need to save those values inside a secure service, either a AWS System Manager (using Parameter Store) or a AWS Secret Manager creating directly a key/value. Why not try both?&lt;/p&gt;
&lt;h4&gt;
  
  
  For Parameter Store
&lt;/h4&gt;

&lt;p&gt;For reusability use the previous encrypted output directly with the same command, getting as result:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws ssm put-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"my-parameter-name"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; &lt;span class="s2"&gt;"SecureString"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws kms encrypt &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="nt"&gt;--key-id&lt;/span&gt; &amp;lt;key &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;--plaintext&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;value&amp;gt;"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text &lt;span class="nt"&gt;--query&lt;/span&gt; CiphertextBlob | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;If everything works, you should receive a json payload like this, which means it works, and that the value was created successfully 👏🏽&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Access via AWS Systems Manager -&amp;gt; Parameter Store to see it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Tier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Standard"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  For Secrets Manager
&lt;/h4&gt;

&lt;p&gt;Secret manager use the same approach as Parameter store, but with a different command, let's see:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws secretsmanager create-secret &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"my-secret"&lt;/span&gt; &lt;span class="nt"&gt;--secret-string&lt;/span&gt; &lt;span class="s2"&gt;"my-secret-value"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Running this will create a new secret in AWS Secrets Manager with the name &lt;code&gt;my-secret&lt;/code&gt; and a secret value of &lt;code&gt;my-secret-value&lt;/code&gt;. If the command is successful, it will return a JSON object containing metadata about the newly created secret, including its &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html" rel="noopener noreferrer"&gt;Amazon Resource Name (ARN)&lt;/a&gt;.&lt;br&gt;
Let's encrypt and send it to &lt;code&gt;secretsmanager&lt;/code&gt; as follow:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

aws secretsmanager create-secret &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"my-secret"&lt;/span&gt; &lt;span class="nt"&gt;--secret-string&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws kms encrypt &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;region&amp;gt; &lt;span class="nt"&gt;--key-id&lt;/span&gt; &lt;span class="nb"&gt;alias&lt;/span&gt;/myprivatekey &lt;span class="nt"&gt;--plaintext&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;value&amp;gt;"&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; text &lt;span class="nt"&gt;--query&lt;/span&gt; CiphertextBlob&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;  &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;region&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;🥳 Getting the following payload means it works:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ARN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:secretsmanager:us-east-1:&amp;lt;account id&amp;gt;:secret:my-secret-j3MXy5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"VersionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;version id&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Access via AWS Secrets Manager -&amp;gt; Secrets to see it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now with both scenarios covered, let's move on and try to access those values from code. Going back to the lambda function, we need to update the code to get and use the value as follow but before let's make sure we can retrieve and decrypt both saved values:&lt;/p&gt;

&lt;p&gt;Check that you are able to decrypt the values, use the command below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Using system manager (parameter store)&lt;/span&gt;
aws kms decrypt &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--ciphertext-blob&lt;/span&gt; fileb://&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;aws ssm get-parameter &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;region&amp;gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"my-parameter-name"&lt;/span&gt; &lt;span class="nt"&gt;--with-decryption&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; Parameter.Value &lt;span class="nt"&gt;--output&lt;/span&gt; text | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--key-id&lt;/span&gt; &lt;span class="nb"&gt;alias&lt;/span&gt;/myprivatekey &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--output&lt;/span&gt; text &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--query&lt;/span&gt; Plaintext | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;

&lt;span class="c"&gt;# For secrets manager&lt;/span&gt;
aws kms decrypt &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--ciphertext-blob&lt;/span&gt; fileb://&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;aws secretsmanager get-secret-value &lt;span class="nt"&gt;--region&lt;/span&gt; &amp;lt;region&amp;gt; &lt;span class="nt"&gt;--secret-id&lt;/span&gt; &lt;span class="s2"&gt;"my-secret"&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; SecretString &lt;span class="nt"&gt;--output&lt;/span&gt; text | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--key-id&lt;/span&gt; &lt;span class="nb"&gt;alias&lt;/span&gt;/myprivatekey &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--output&lt;/span&gt; text &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--query&lt;/span&gt; Plaintext | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;✨ You should be able to get you real value, in our case was &lt;code&gt;my precious value&lt;/code&gt; (base64 encoded at start). Here is what the test code implementation could look like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;This should be the output from logs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

START RequestId: xxxxxxx Version: &lt;span class="nv"&gt;$LATEST&lt;/span&gt;
2023-04-15T21:51:48.684Z xxxxxxx INFO from parameters store: my precious value
2023-04-15T21:51:48.684Z xxxxxxx INFO from secrets manager: my precious value
END RequestId: xxxxxxx
REPORT RequestId: xxxxxxx Duration: 255.71 ms Billed Duration: 256 ms Memory Size: 1024 MB Max Memory Used: 97 MB Init Duration: 699.66 ms


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;All the code is available &lt;a href="https://github.com/frangeris/post-secure-private-keys-using-kms" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you want to test it.&lt;/p&gt;

&lt;p&gt;Hope it helps, cheers 🍻&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>serverless</category>
      <category>devops</category>
    </item>
    <item>
      <title>Reverse proxy cache using AWS CloudFront</title>
      <dc:creator>Frangeris Peguero</dc:creator>
      <pubDate>Mon, 28 Nov 2022 16:00:43 +0000</pubDate>
      <link>https://dev.to/cloudx/reverse-proxy-cache-using-aws-cloudfront-g5k</link>
      <guid>https://dev.to/cloudx/reverse-proxy-cache-using-aws-cloudfront-g5k</guid>
      <description>&lt;h2&gt;
  
  
  How to implement a reverse proxy cache to any API using AWS CloudFront
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A reverse proxy is the application that sits in front of back-end applications and forwards client (e.g. browser) requests to those applications. Reverse proxies help increase scalability, performance, resilience and security. The resources returned to the client appear as if they originated from the web server itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html" rel="noopener noreferrer"&gt;AWS CloudFront&lt;/a&gt; is a &lt;a href="https://en.wikipedia.org/wiki/Content_delivery_network" rel="noopener noreferrer"&gt;CDN service&lt;/a&gt; for high performance and security convenience that offers a lot of advantages including a global edge network with a low latency and high throughput network connectivity (the one that matter to us).&lt;/p&gt;

&lt;p&gt;One typical example where we could be needing a reverse proxy cache mechanism is when building HTTP APIs (API Gateway v2) on AWS, this type of APIs are designed with minimal features so that they can be offered at lower price, lacking options as edge optimization, support for api keys, throttling and cache, &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html" rel="noopener noreferrer"&gt;more detailed comparison here&lt;/a&gt;; not having support for cache means processing time load will increase on backend side on origin servers, resulting in high latency on every request.&lt;/p&gt;

&lt;p&gt;As it turns out, CloudFront solves this problem nicely.&lt;/p&gt;

&lt;p&gt;For simplicity we will be using &lt;a href="https://www.serverless.com/framework/docs" rel="noopener noreferrer"&gt;Serverless Framework v3&lt;/a&gt; to handle AWS stack creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start by creating a HTTP API (&lt;em&gt;API Gateway v2&lt;/em&gt;)
&lt;/h2&gt;

&lt;p&gt;A very basic serverless api deployment should be working and usable to be able to configure CloudFormation distribution on top of it.&lt;/p&gt;

&lt;p&gt;If you don't have previous experience with serverless, follow this &lt;a href="https://www.serverless.com/framework/docs/tutorial" rel="noopener noreferrer"&gt;link&lt;/a&gt; on how to do it, just remember to select &lt;strong&gt;"HTTP API"&lt;/strong&gt; as is the one that doesn't have cache support already built in.&lt;/p&gt;

&lt;p&gt;Let's start by defining the type of api we need and some basic function to be able to exemplify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# serverless.yml&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;myapi"&lt;/span&gt;
    &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hello&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/handler.hello&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regarding to what data we will be returning, lets run a process that sleep for 5 seconds to simulate some background process that "take too long" to complete using the &lt;a href="https://nodejs.org/api/timers.html#timers-promises-api" rel="noopener noreferrer"&gt;&lt;code&gt;Timers API&lt;/code&gt;&lt;/a&gt;, something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F02.image.2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F02.image.2.png" alt="Basic hello lambda function triggered by a GET request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎉 After a correct deployment, the api should be created successfully and ready to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F02.image.1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F02.image.1.png" alt="Serverless deployment with a success result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that the API is live and usable, we can make request by just calling the endpoint provided:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="s1"&gt;'https://644z4ooroe.execute-api.us-east-1.amazonaws.com/'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will return the response we explicitly send back in our lambda, &lt;strong&gt;BUT&lt;/strong&gt;, &lt;em&gt;after 5 seconds&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F02.image.3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F02.image.3.png" alt="Postman request response from origin endpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you notice the time taken to complete the request &lt;code&gt;5.21s&lt;/code&gt; is the time we setup to sleep, this time is also influenced by the spin up (known as freeze time) of lambdas, consecutive requests will decrease the time needed by the script to return data but only by a few ms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So what happens if we cache this response not to wait those &lt;code&gt;5s&lt;/code&gt; of processing time?&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's configure CloudFront as a reverse proxy
&lt;/h2&gt;

&lt;p&gt;The process consists in creating a distribution using the API domain as origin, enabling the built-in cache inside the distribution and controlling the caching time by TTL.&lt;/p&gt;

&lt;p&gt;Following the &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_CloudFront.html" rel="noopener noreferrer"&gt;Amazon CloudFront resource type reference&lt;/a&gt; we will create the distribution directly from serverless template and connect it to the previous created API as our origin.&lt;/p&gt;

&lt;p&gt;We need to create two resources to be able to create the distribution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AWS::CloudFront::CachePolicy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS::CloudFront::Distribution&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside the &lt;code&gt;serverless.yml&lt;/code&gt; file (at the end), let's create a new section: &lt;code&gt;resources&lt;/code&gt; where we can add resources that will be created for us inside AWS by the &lt;code&gt;sls deploy&lt;/code&gt; command, those resources are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-cachepolicy.html&lt;/span&gt;
    &lt;span class="na"&gt;mycachepolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::CloudFront::CachePolicy&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;CachePolicyConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mycachepolicy&lt;/span&gt;
          &lt;span class="c1"&gt;# We can custom or TTL values below&lt;/span&gt;
          &lt;span class="na"&gt;DefaultTTL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;86400&lt;/span&gt;
          &lt;span class="na"&gt;MaxTTL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;86400&lt;/span&gt;
          &lt;span class="na"&gt;MinTTL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
          &lt;span class="na"&gt;ParametersInCacheKeyAndForwardedToOrigin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;EnableAcceptEncodingGzip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;EnableAcceptEncodingBrotli&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;CookiesConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;CookieBehavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
            &lt;span class="na"&gt;HeadersConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;HeaderBehavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
            &lt;span class="na"&gt;QueryStringsConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;QueryStringBehavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;

    &lt;span class="c1"&gt;# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html&lt;/span&gt;
    &lt;span class="na"&gt;mydistribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::CloudFront::Distribution&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;DistributionConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;Origins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# auto generated by serverless, also removed "http:" as is not allowed in domain name, is going to use the default API URL generated by AWS, if you have a custom api url, just replace it here&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;DomainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="kt"&gt;!Select&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Split&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;//"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="nv"&gt;HttpApi.ApiEndpoint&lt;/span&gt;&lt;span class="pi"&gt;]]&lt;/span&gt;
              &lt;span class="c1"&gt;# this value should be moved to a custom global var instead of duplicating the same string below&lt;/span&gt;
              &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mydistributiondomainid&lt;/span&gt;
              &lt;span class="na"&gt;CustomOriginConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;OriginProtocolPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https-only&lt;/span&gt;
          &lt;span class="na"&gt;DefaultCacheBehavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;CachePolicyId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;mycachepolicy&lt;/span&gt;
            &lt;span class="na"&gt;DefaultTTL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
            &lt;span class="na"&gt;TargetOriginId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mydistributiondomainid&lt;/span&gt;
            &lt;span class="na"&gt;ViewerProtocolPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https-only&lt;/span&gt;
            &lt;span class="c1"&gt;# List of allowed method acceded by cache, only GET for our case&lt;/span&gt;
            &lt;span class="na"&gt;AllowedMethods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;GET&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;HEAD&lt;/span&gt;
          &lt;span class="c1"&gt;# all means all edge locations (recommended)&lt;/span&gt;
          &lt;span class="na"&gt;PriceClass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PriceClass_All&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dont forget to run the re-deploy to update the AWS stack with the new config, if everything works, we should be able to make request to the cloudfront URL and it will cache the responses from the origin.&lt;/p&gt;

&lt;p&gt;⚡️ Here is the final requests, the first is to our origin, the second to cloudfront cache.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F02.image.4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fcloudx-labs%2Fposts%2Fmain%2Fposts%2Ffrangeris%2Fassets%2F02.image.4.gif" alt="Postman final response for origin and cache"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🤯 As we can see, the response time is absurd in comparison just by enabling a cache.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember the very first request (&lt;a href="https://docs.amazonaws.cn/en_us/AmazonCloudFront/latest/DeveloperGuide/understanding-the-cache-key.html" rel="noopener noreferrer"&gt;miss cloudfront&lt;/a&gt;) will have the same load time as the origin due to will populate the first time the cache.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All the code is available &lt;a href="https://github.com/frangeris/example-reverse-proxy-cache-cloudfront" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you want to test it.&lt;/p&gt;

&lt;p&gt;Hope it helps, cheers 🍻&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>aws</category>
      <category>cache</category>
      <category>cloudfront</category>
    </item>
    <item>
      <title>Reusable dynamic modal on Vue 3</title>
      <dc:creator>Frangeris Peguero</dc:creator>
      <pubDate>Wed, 26 Oct 2022 17:37:02 +0000</pubDate>
      <link>https://dev.to/cloudx/reusable-dynamic-modal-on-vue-3-1k56</link>
      <guid>https://dev.to/cloudx/reusable-dynamic-modal-on-vue-3-1k56</guid>
      <description>&lt;h2&gt;
  
  
  Reusable dynamic modal on Vue 3
&lt;/h2&gt;

&lt;p&gt;Most of the time on frontend development the best way to keep a consistent way of building components is trying to make them reusable every time we can, but sometimes the framework itself can make it a bit hard if we don’t have deep knowledge of its internal API, specifically the way it handles view instance and state component data.&lt;/p&gt;

&lt;p&gt;What makes a good reusable modal?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Dynamic views&lt;/li&gt;
&lt;li&gt;✅ Customizable actions with callbacks (buttons)&lt;/li&gt;
&lt;li&gt;✅ easy-peasy instantiation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For simplicity we will be using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://daisyui.com" rel="noopener noreferrer"&gt;DaisyUI&lt;/a&gt; as component library (&lt;a href="https://daisyui.com/components/modal/" rel="noopener noreferrer"&gt;modal&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pinia.vuejs.org/" rel="noopener noreferrer"&gt;Pinia&lt;/a&gt; as state management vue store&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue 3&lt;/a&gt; with the composition API &lt;a href="https://vuejs.org/guide/typescript/overview.html" rel="noopener noreferrer"&gt;with typescript&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s start by defining a very basic modal template using daisy classes:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="c"&gt;&amp;lt;!-- @/components/x-modal.vue --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal modal-open"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-box relative"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-sm btn-circle absolute right-2 top-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;✕&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hey, it works 👏🏽&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To be able to access it from anywhere and render any type of view, the modal needs to be accessible from any component that wants to use it, for this reason the modal component needs to be placed on the root parent view where all the views will be rendered, assuming &lt;a href="https://router.vuejs.org/" rel="noopener noreferrer"&gt;Vue router&lt;/a&gt; is being used:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;x-modal&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;router-view&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;XModal&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/components/x-modal.vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;👏🏽 You should be able to see our beautiful modal rendered!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup the store (state management)
&lt;/h2&gt;

&lt;p&gt;As it's a reusable global modal, we need to keep &lt;em&gt;global&lt;/em&gt; track if this modal is opened or closed and also have the ability to control it from any other component, maintaining a unique instance. This is where Pinia comes in.&lt;/p&gt;

&lt;p&gt;Lets define a new store specifically to interact with the modal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// @/store/modal.ts&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;markRaw&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineStore&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pinia&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Modal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ModalAction&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="nx"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ModalAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&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="k"&gt;void&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;useModal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modal&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;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Modal&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&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="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="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ModalAction&lt;/span&gt;&lt;span class="p"&gt;[])&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="nx"&gt;isOpen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// using markRaw to avoid over performance as reactive is not required&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;markRaw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&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="nx"&gt;isOpen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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="nx"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&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;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;useModal&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now we have the store, lets connect it to our modal template so we can use its reactive references:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- isOpen is reactive and taken from the store, define if it is rendered or not --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"isOpen"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal modal-open"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-box relative"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- @click handles the event to close the modal calling the action directly in store --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt;
          &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn btn-sm btn-circle absolute right-2 top-2"&lt;/span&gt;
          &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"modal.close()"&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;✕&lt;span class="nt"&gt;&amp;lt;/label&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="c"&gt;&amp;lt;!-- dynamic components, using model to share values payload --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;component&lt;/span&gt; &lt;span class="na"&gt;:is=&lt;/span&gt;&lt;span class="s"&gt;"view"&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"model"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/component&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal-action"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="c"&gt;&amp;lt;!-- render all actions and pass the model payload as parameter --&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
            &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"action in actions"&lt;/span&gt;
            &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn"&lt;/span&gt;
            &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"action.callback(model)"&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            {{ action.label }}
          &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;reactive&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;storeToRefs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pinia&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useModal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/stores&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;modal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// reactive container to save the payload returned by the mounted view&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reactive&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;

  &lt;span class="c1"&gt;// convert all state properties to reactive references to be used on view&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;storeToRefs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;component&amp;gt;&lt;/code&gt; is the way that &lt;code&gt;vue&lt;/code&gt; handle dynamic components where &lt;code&gt;:is&lt;/code&gt; receive the view that needs to be rendered, more info &lt;a href="https://vuejs.org/api/built-in-special-elements.html#component" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It also support using the &lt;code&gt;v-model&lt;/code&gt; directive to be able to share values dynamically, but how does this works?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once we have the view mounted inside &lt;code&gt;&amp;lt;component&amp;gt;&lt;/code&gt; we can make use of &lt;code&gt;v-model&lt;/code&gt; to send and update reactive references emitting events from the view we are mounting. Internally from the view we want to render: &lt;code&gt;emit&lt;/code&gt; a &lt;code&gt;"update:modelValue"&lt;/code&gt; event that will update the reference passed via &lt;code&gt;v-model&lt;/code&gt; back, eg:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="c"&gt;&amp;lt;!-- MyViewToRender.vue --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;watch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// no need to import defineEmits&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineEmits&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;update:modelValue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="c1"&gt;// when someVar changes, it will update the reference passed via v-model&lt;/span&gt;
  &lt;span class="nf"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someVar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&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="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;update:modelValue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Make use of the modal
&lt;/h2&gt;

&lt;p&gt;To be able to control and populate data into the modal, we'll use the store defined as follow:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"handleOnClickOpenModal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Open&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;useModal&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/stores/modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyViewToRender&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/views/MyViewToRender.vue&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;modal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleOnClickOpenModal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MyViewToRender&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;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Save&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataFromView&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dataFromView&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When a click event on the &lt;code&gt;button&lt;/code&gt; occurs, it will call &lt;code&gt;handleOnClickOpenModal&lt;/code&gt; which at the same time will call the &lt;code&gt;open&lt;/code&gt; action from the store, which changes the &lt;code&gt;isOpen&lt;/code&gt; variable from the state, and as the modal is observing this value it will render or not depending of the value as follow:&lt;/p&gt;

&lt;p&gt;🎉 Hurra!!! you have made a reusable modal on top of composition API and pinia.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexzuhf35em2pnevterxt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexzuhf35em2pnevterxt.gif" alt="Dynamic modal on vue 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What if we want to pass a payload to our view?
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Dependency injection is a programming technique / design pattern in which an object or function receives other objects or functions that it depends on.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Vue natively implements a mechanism to handle this pattern, this implementation is known as &lt;code&gt;Provide / Inject&lt;/code&gt;, more info &lt;a href="https://vuejs.org/guide/components/provide-inject.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. A parent component can serve as a dependency provider for all its descendants. Any component in the descendant tree, regardless of how deep it is, can inject dependencies provided by components up in its parent chain. The issue with this approach is that it only applies to direct descendants from parent (not parallel components) and as the modal view is not strictly a child of the component invoking it, it won't work as intended.&lt;/p&gt;

&lt;p&gt;Another way is to add a field property to the state of the modal on pinia (&lt;em&gt;payload&lt;/em&gt;) and pass any reactive references from there, and then receive that object from the view we render.&lt;/p&gt;

&lt;p&gt;Hope it helps, cheers 🍻&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
