<?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: Claranet</title>
    <description>The latest articles on DEV Community by Claranet (@claranet).</description>
    <link>https://dev.to/claranet</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%2Forganization%2Fprofile_image%2F6685%2F9b4c0121-6fdd-47b7-bfa0-496cff974af3.png</url>
      <title>DEV Community: Claranet</title>
      <link>https://dev.to/claranet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/claranet"/>
    <language>en</language>
    <item>
      <title>From Static Pages to Interactive Spaces: Embedding Now4Real Chat</title>
      <dc:creator>Gianluca La Manna</dc:creator>
      <pubDate>Tue, 23 Sep 2025 10:37:02 +0000</pubDate>
      <link>https://dev.to/claranet/from-static-pages-to-interactive-spaces-embedding-now4real-chat-4p4n</link>
      <guid>https://dev.to/claranet/from-static-pages-to-interactive-spaces-embedding-now4real-chat-4p4n</guid>
      <description>&lt;p&gt;Today I want to show a cool thing. Have you never thought to chat instantly inside a specific web page with other people who share the same interest?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://now4real.com/" rel="noopener noreferrer"&gt;Now4Real&lt;/a&gt; is an excellent solution for that.&lt;/p&gt;

&lt;p&gt;We at Claranet Italy have made this integration with a web management software: &lt;a href="https://www.logicasolutions.it/" rel="noopener noreferrer"&gt;Logica&lt;/a&gt; by Sinapsi SB.&lt;/p&gt;

&lt;p&gt;Now I show how we did it and how simple it is to integrate this tool into every web page.&lt;/p&gt;

&lt;p&gt;First of all, we have to create an account on &lt;a href="https://now4real.com/" rel="noopener noreferrer"&gt;https://now4real.com/&lt;/a&gt;, and then we will have to access the dashboard like this:&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%2Fi7ialpf1sgmqusogcjde.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%2Fi7ialpf1sgmqusogcjde.png" alt="Now4real Dashboard" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the bottom right corner, we have the chat icon, and this keeps track of the people, in that specific moment, who are showing the same page as you.&lt;/p&gt;

&lt;p&gt;Inside it, we can chat with other people and share knowledge about the page, or share the same interests or something like that.&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%2Fbqxe9jwsjhud66dnkd2l.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%2Fbqxe9jwsjhud66dnkd2l.png" alt="Now4real Chat" width="321" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's move to the practice.&lt;/p&gt;

&lt;p&gt;From the dashboard, we have to add a new site.&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%2Fj2p60ehj80eqau6jr49n.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%2Fj2p60ehj80eqau6jr49n.png" alt="Public domain" width="768" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Important: Here we have to use a public domain.&lt;/p&gt;

&lt;p&gt;Now, inside index.html of our application, we have to add this line of code:&lt;br&gt;
&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;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"now4real-site-verification"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"XXXXX"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where XXXXX is a key provided by now4Real when you add the new site.&lt;/p&gt;

&lt;p&gt;Commit and publish this modification to link the site with now4real.&lt;/p&gt;

&lt;p&gt;Then we can manage the JWT authentication, because we want to use a logged-in user inside of Logica. So, if I log on to Logica with the Angelo user, I want to use the chat with the same user.&lt;/p&gt;

&lt;p&gt;To do this, go to the menu dashboard under the Authentication menu item and generate a shared secret&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%2F6m69e27wszdg60pqewz3.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%2F6m69e27wszdg60pqewz3.png" alt="Authentication settings" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, you have a lot of configuration on the side of the menu. We will show something later.&lt;/p&gt;

&lt;p&gt;Now we need a JWT signed with the algorithm HS256, and use it inside the now4real object, like this:&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now4real&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now4real&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="nx"&gt;now4real&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api+widget&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;page&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="na"&gt;custom_auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="na"&gt;page_context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getPageContextFromHash&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;Here are some considerations:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;target&lt;/code&gt; is api+widget by now4real documentation to istantiate the service&lt;br&gt;
&lt;code&gt;scope&lt;/code&gt;, we want to use this to enable different chats per page.&lt;br&gt;
&lt;code&gt;custom_auth&lt;/code&gt; to use the authentication inside the chat&lt;br&gt;
&lt;code&gt;page_context&lt;/code&gt;to use the discriminant per page, for example an id.&lt;/p&gt;

&lt;p&gt;To remove the chat from some pages, currently we can remove the widget from the DOM like this:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;removeNow4RealFromDom&lt;/span&gt; &lt;span class="o"&gt;=&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NOW4REAL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nf"&gt;remove&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;SCRIPT_REGEX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/.*now4real&lt;/span&gt;&lt;span class="se"&gt;\.(&lt;/span&gt;&lt;span class="sr"&gt;min&lt;/span&gt;&lt;span class="se"&gt;\.)?&lt;/span&gt;&lt;span class="sr"&gt;js/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;script&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;SCRIPT_REGEX&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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="s2"&gt;`Removed Now4Real script: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;isInitialized&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;delete&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;now4real&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;Maybe we will have a new api from Now4real to manage this specific case.&lt;/p&gt;

&lt;p&gt;Cool things&lt;br&gt;
From the dashboard, we are able to manage the styles and position of our chat component&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%2Fvshussaibw5060ppj9i4.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%2Fvshussaibw5060ppj9i4.png" alt="Style settings" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can publish instantly the modifications.&lt;/p&gt;

&lt;p&gt;Or manage the messages&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%2Fimkwwmxhhwpdjfqqgfny.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%2Fimkwwmxhhwpdjfqqgfny.png" alt="Message settings" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;with message duration, or block specific words or offensive language&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%2F7343n0so0rn29u8c6o9v.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%2F7343n0so0rn29u8c6o9v.png" alt="Language settings" width="800" height="745"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading. See you next time 👋🏻&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>code</category>
    </item>
    <item>
      <title>Mobile development best practices</title>
      <dc:creator>Francesco Mariani</dc:creator>
      <pubDate>Tue, 09 Sep 2025 07:03:37 +0000</pubDate>
      <link>https://dev.to/claranet/mobile-development-best-practices-24on</link>
      <guid>https://dev.to/claranet/mobile-development-best-practices-24on</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Today, mobile applications are at the forefront of user engagement, brand presence, and business growth. With the spread of multiple platforms, it’s essential to develop robust, scalable, and user-friendly mobile apps. This requires more than just coding skills, and it demands a solid grasp of best practices and deep platform knowledge to ensure long-term success and maintainability.&lt;/p&gt;

&lt;p&gt;This article explores essential best practices in mobile development for building UIs aligned with iOS and Android platform guidelines, preserving usability, and managing upgrades to safeguard backward compatibility.&lt;/p&gt;

&lt;p&gt;Next, we examine the critical roles of automated testing and CI/CD.&lt;/p&gt;

&lt;p&gt;Finally, we’ll look at strategies for efficient data handling&lt;/p&gt;

&lt;h2&gt;
  
  
  Usability
&lt;/h2&gt;

&lt;p&gt;When developing a project for iOS and Android, it is essential to adhere to the usability guidelines specific to each platform to ensure a consistent, intuitive, and accessible user experience.&lt;/p&gt;

&lt;p&gt;You can refer to the official guidelines provided by Apple and Android&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://developer.apple.com/design/human-interface-guidelines/" rel="noopener noreferrer"&gt;iOS – Human Interface Guidelines (HIG)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://m3.material.io/" rel="noopener noreferrer"&gt;Android – Material Design Guidelines&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, we look at some of the usability rules, first with iOS and then Android:&lt;/p&gt;

&lt;h2&gt;
  
  
  IOS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Depth, clarity, and deference (subtle and unobtrusive interface design).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The app uses subtle shadows, blurs, and transitions to show hierarchy between components.&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%2Fhqolun0murp5llixftfd.jpg" 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%2Fhqolun0murp5llixftfd.jpg" alt="ISO" width="654" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Top navigation bar with cantered titles
&lt;/h2&gt;

&lt;p&gt;Centering titles in the top navigation bar reinforces platform consistency, offers immediate screen context, and contributes to a balanced, intuitive layout that aligns with iOS user expectations.&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%2F1ok2vzvx5p7hu9hc9653.jpg" 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%2F1ok2vzvx5p7hu9hc9653.jpg" alt="ISO" width="334" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom tab bar for primary sections
&lt;/h2&gt;

&lt;p&gt;A bottom tab bar is essential for organizing an app’s main sections. It gives users immediate, consistent access to the app’s core areas, improving discoverability and reducing navigation steps. This aligns with iOS design principles by prioritizing simplicity and directness for frequent tasks.&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%2Fqzciy64tr00mgm1b4rk1.jpg" 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%2Fqzciy64tr00mgm1b4rk1.jpg" alt="ISO" width="351" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Back gesture: swipe from left to right.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The swipe-from-left-edge back gesture makes navigation more fluid and natural, letting users move backward with a quick, intuitive swipe. It reduces reliance on tap targets, speeds up interaction, and aligns with iOS’s focus on gesture-driven, edge-to-edge experiences.&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%2Fenf5cqpzbs7wxs85y1er.jpg" 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%2Fenf5cqpzbs7wxs85y1er.jpg" alt="ISO" width="563" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minimalism: Apple promotes a clean and restrained design.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apple consistently advocates for minimalistic design principles, emphasizing clarity, focus, and simplicity. Their interfaces use generous white space, subtle color palettes, and intuitive layouts that prioritize essential content, reducing cognitive load. This approach not only enhances aesthetics but also improves usability by guiding users naturally through tasks without unnecessary distractions.&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%2F9wsvmzijpmuh78qms8m0.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%2F9wsvmzijpmuh78qms8m0.png" alt="ISO" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Native components: UISwitch, UITableView, UICollectionView, etc.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apple’s native UI components, such as UISwitch, UITableView, and UICollectionView, are fundamental building blocks of iOS applications. These standardized elements provide consistent behavior, accessibility, and visual style across apps. With the use of native controls, developers ensure seamless integration with system conventions, improve performance, and deliver a familiar experience that aligns with Apple’s Human Interface Guidelines.&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%2Fdat2h6z429x3ov8xzkrx.jpg" 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%2Fdat2h6z429x3ov8xzkrx.jpg" alt="ISO" width="344" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dark Mode: supporting is highly recommended&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Dark Mode has become a standard expectation in modern mobile applications as it provides users with an alternative appearance that reduces eye strain and saves battery life on OLED screens. With system-driven dark appearances, developers ensure consistent theming, seamless transitions between light and dark modes, and adherence to user preferences. Supporting Dark Mode not only enhances accessibility and comfort but also aligns with platform guidelines, improving the overall quality and professionalism of the app.&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%2Fmeh5lpqnmhjqsq0lc387.jpg" 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%2Fmeh5lpqnmhjqsq0lc387.jpg" alt="ISO" width="303" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Android
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Material You: dynamic theming based on the user’s system theme and preferences.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Material You is a personalized design system that adapts its appearance based on the user's preferences and current system theme. It dynamically changes color schemes, typography, and other user interface elements to create a cohesive and customizable experience that feels unique to each user. This approach enhances the aesthetic appeal of an app and boosts usability and accessibility, making interactions more intuitive based on user's habitual patterns and preferences.&lt;/p&gt;


  


&lt;p&gt;&lt;strong&gt;Floating Action Button (FAB) for primary actions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Floating Action Button (FAB) is a hallmark of Material Design, designed to promote a primary action within an app, such as composing a new message, adding a new contact, or creating a new document. Its distinguished circular shape and elevated position over the interface command user attention, making it easily accessible while not interfering with other UI elements. FAB supports a better user experience by providing a consistent and recognizable action button.&lt;/p&gt;


  


&lt;p&gt;&lt;strong&gt;Navigation Drawer or Bottom Navigation for main navigation structures.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigation drawers and bottom navigation bars are critical components in structuring and accessing major areas of an app efficiently. The navigation drawer slides out from the side and is ideal for accessing a wide range of options without cluttering the primary interface. In contrast, bottom navigation bars provide visible at-a-glance views for top-level destinations. Both elements facilitate seamless navigation across the app's different sections, enhancing usability with clear, reachable pathways.&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%2Fy0u4q7ey3rwxz4pdxd6q.jpg" 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%2Fy0u4q7ey3rwxz4pdxd6q.jpg" alt="ISO" width="629" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Physical or gesture-based back button: pressing the back button with a modal or overlay open should dismiss the modal, not navigate back to the previous screen.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Proper utilization of the back button ensures an intuitive navigation. Whether it's a physical button or a gesture-based control, pressing the back button should first close any active modals or overlays. This makes sure that the user doesn't unintentionally exit the current context or lose unsaved changes, thus maintaining a logical progression through app content and preventing potential frustration from unexpected navigation actions.&lt;/p&gt;


  


&lt;p&gt;&lt;strong&gt;Standard Material components: Button, Card, Chip, Snackbar, etc.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Standard Material components such as Buttons, Cards, Chips, and Snackbars play key roles in creating a consistent and functional user interface. Each component serves distinct purposes: Buttons are for actions; Cards for grouping related information in a flexible container; Chips for compact elements representing input, attribute, or action; and Snackbars for brief messages about app processes. These components are designed for versatility and scalability across different platforms and provide a unified design language and interaction consistency.&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%2Fs499za9q4avh1bjuihsu.jpg" 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%2Fs499za9q4avh1bjuihsu.jpg" alt="Anroid" width="604" height="180"&gt;&lt;/a&gt;&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%2Fy0ph9nhj3i2zzkek38pb.jpg" 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%2Fy0ph9nhj3i2zzkek38pb.jpg" alt="Anroid" width="238" height="242"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Meaningful animations: transitions, elevation effects, and interaction feedback.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Meaningful animations enhance user experience by providing visual cues that depict relationships, hierarchy, and functionality. Smooth transitions guide users between app states with clear movement that respects context, improving cognitive recognition of app structure. Elevation effects create depth and focus attention, while interaction feedback animations reassure users of their actions, such as button presses or toggling settings, establishing a satisfying interaction that confirms user inputs have been recognized and processed.&lt;/p&gt;


  


&lt;p&gt;There are also common best practices shared by iOS and Android that are useful in the daily use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Design &amp;amp; test: use tools like Figma, Sketch, Adobe XD, and conduct testing with real users.&lt;/li&gt;
&lt;li&gt;  Respect platform differences: avoid forcing the behaviour of one platform onto the other.&lt;/li&gt;
&lt;li&gt;  Continuous update: stay aligned with the evolving Apple/Google guidelines and plan for continuous delivery, potentially leveraging a release pipeline.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  WCAG Compliance Check
&lt;/h2&gt;

&lt;p&gt;To verify whether an app is compliant with the WCAG, you can refer to the following specifically tailored for mobile accessibility:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.w3.org/WAI/standards-guidelines/mobile/" rel="noopener noreferrer"&gt;https://www.w3.org/WAI/standards-guidelines/mobile/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After reviewing the WCAG guidelines, you need to check if your app complies with them. In the next chapter, we’ll look at some testing tools to help you do that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility test tools
&lt;/h2&gt;

&lt;p&gt;Both Android and iOS offer various frameworks for unit, UI, and integration testing, but finding the right tools to test accessibility can be more challenging.&lt;/p&gt;

&lt;p&gt;Let’s describe some of them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IOS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Xcode Accessibility Inspector:&lt;/strong&gt; Xcode tool for display, query, and test accessibility information for the elements in your app’s view hierarchy.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;VoiceOver:&lt;/strong&gt; Built-in screen reader for Apple devices that enables users to interact with their devices using spoken and tactile feedback instead of visual cues.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/markbattistella/ContrastKit" rel="noopener noreferrer"&gt;ContrastKit&lt;/a&gt;: Is a Swift library design to facilitate colour contrast handling within iOS, IPadOS, macOS and tvOS applications.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Colour Contrast Calculator:&lt;/strong&gt; Xcode’s tool to compute contrast between any two colours and use those colours for images used between normal and high-contrast mode. To open it, you can go to: ‘Open Developer tools &amp;gt; Accessibility Inspector &amp;gt; Window &amp;gt; Show Contrast Calculator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Android&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Accessibility Scanner&lt;/strong&gt; (Google): You can download it from the Play store. The scanner records the current screen and provides you tips to improve accessibility of your app based on the following elements: labels, touch target size, clickable elements, text and image contrast.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TalkBack:&lt;/strong&gt; this is a screen reader for Android devices, developed by Google, that provides spoken and braille feedback to help users with visual impairments interact with their devices.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Layout Inspector&lt;/strong&gt; (included in Android Studio): this Android studio tools lets you debug the app layout by showing a view hierarchy where you can inspect the properties of each view.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Android Accessibility Test Framework (ATF) with Espresso&lt;/strong&gt;: it works with Espresso, a popular testing framework, and automatically looks for common accessibility issues like missing labels or low contrast during UI tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data management and synchronization
&lt;/h2&gt;

&lt;p&gt;After discussing the UI, let’s look at how to handle the data in the following possible scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Handling small amounts of data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this case the structure is primarily key value based, Android’s SharedPreferences and iOS’s UserDefaults are typically used.&lt;/p&gt;

&lt;p&gt;To synchronize this information online -to enable the user to access the same app data across multiple devices or after reinstalling the app- we can find various online services, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Firebase Remote Config:&lt;/strong&gt; ideal for feature flags and configuration settings.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;iCloud Key-Value Store:&lt;/strong&gt; iOS-only, perfect for user settings, preferences, and app state, with a 1MB maximum limit.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Firebase Realtime Database or Firestore&lt;/strong&gt;: enables real-time automatic synchronization, commonly used for shared data across devices, configurations, app state, and user preferences.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can summarize using the following table:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tbody&gt;
&lt;tr&gt;
    &lt;th&gt;Level&lt;/th&gt;
    &lt;th&gt;Tool&lt;/th&gt;
    &lt;th&gt;Scope&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Local&lt;/td&gt;
    &lt;td&gt;SharedPreferences / UserDefaults&lt;/td&gt;
    &lt;td&gt;Cache and offline access&lt;/td&gt;
  &lt;/tr&gt;
    &lt;tr&gt;
    &lt;td&gt;Synchronization&lt;/td&gt;
    &lt;td&gt;Firestore / REST API&lt;/td&gt;
    &lt;td&gt;Backup and synchronization between devices&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Sensitive data&lt;/td&gt;
    &lt;td&gt;Keychain / Secure Storage&lt;/td&gt;
    &lt;td&gt;Token, password&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
      &lt;td&gt;Dynamic configurations&lt;/td&gt;
      &lt;td&gt;Firebase Remote Config / ICloud Key-Value&lt;/td&gt;
      &lt;td&gt;Feature toggle, A/B testing&lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Management and synchronization of large amounts of data
&lt;/h2&gt;

&lt;p&gt;In this case, you will most likely manage a Room database for Android, Core Data for iOS, SQLite for Flutter, and WatermelonDB for React Native.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tbody&gt;
&lt;tr&gt;
    &lt;th&gt;Stack&lt;/th&gt;
    &lt;th&gt;Local DB&lt;/th&gt;
    &lt;th&gt;Recommended Sync&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Android&lt;/td&gt;
    &lt;td&gt;Room / SQLite&lt;/td&gt;
    &lt;td&gt;WorkManager + Retrofit / Firestore SDK&lt;/td&gt;
  &lt;/tr&gt;
    &lt;tr&gt;
    &lt;td&gt;iOS&lt;/td&gt;
    &lt;td&gt;CoreData&lt;/td&gt;
    &lt;td&gt;CloudKit / API REST&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;Flutter&lt;/td&gt;
    &lt;td&gt;sqflite&lt;/td&gt;
    &lt;td&gt;Cloud Firestore / REST&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
      &lt;td&gt;React Native&lt;/td&gt;
      &lt;td&gt;WatermelonDB&lt;/td&gt;
      &lt;td&gt;Custom sync / Firebase&lt;/td&gt;
  &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Below are some best practices for database management:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Change tracking&lt;/strong&gt;: use fields such as lastModified, syncStatus, version.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Migration&lt;/strong&gt;: create a migration for every app version upgrade and write automated tests to validate the migration.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Conflict management&lt;/strong&gt;: use strategies like "Last Write Wins," logical merge, or centralized control.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Flexibility&lt;/strong&gt;: keep the data model independent from the database (DTO ↔ Entity).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Network&lt;/strong&gt;: detect network status before attempting sync; provide offline fallback.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Security&lt;/strong&gt;: authentication (JWT, OAuth2), mandatory HTTPS, secure token management.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Intelligent sync&lt;/strong&gt;: trigger sync on events (e.g., login, data changes), timers, or network conditions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Backup &amp;amp; Restore&lt;/strong&gt;: offer manual/automatic backups to cloud services or exportable files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Update Management &amp;amp; Backward Compatibility
&lt;/h2&gt;

&lt;p&gt;To ensure API stability across different app versions, it is essential to follow the following best practices:&lt;/p&gt;

&lt;h2&gt;
  
  
  API Versioning and Management
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Use API versioning (e.g., /api/v1/)&lt;/strong&gt;: for each major release, it is recommended to maintain a dedicated API version.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Maintain backward compatibility&lt;/strong&gt;: avoid breaking changes while previous app versions are still in use.&lt;/li&gt;
&lt;li&gt;  Gradually deprecate obsolete APIs that are no longer used.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Server-side feature flags&lt;/strong&gt;: enable or disable features on the server side to prevent crashes in outdated app versions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Check the client version in the API&lt;/strong&gt;: send the app version in the request headers and tailor the response accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Environment management and testing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Separate environments for dev/staging/prod (including for APIs).&lt;/li&gt;
&lt;li&gt;  Mock APIs to test new features without affecting real data.&lt;/li&gt;
&lt;li&gt;  Automated and manual testing across multiple API and app versions.&lt;/li&gt;
&lt;li&gt;  Unit tests, UI tests (Espresso, XCTest), and integration tests.&lt;/li&gt;
&lt;li&gt;  Backward compatibility testing: test the new app against old APIs and vice versa, and handle exceptions accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Progressive rollout and rollback&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A staged rollout deployment is useful and safe, it consists in releasing an app gradually to a small percentage of users first, then spreading it to more users in later phases. This approach helps to detect issues early, limits the impact of bugs, and ensures stability before the update becomes public.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Google Play → release to a percentage of users or test groups.&lt;/li&gt;
&lt;li&gt;  App Store → TestFlight or release to geographic groups or small batches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monitoring tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Firebase Crashlytics,&lt;/li&gt;
&lt;li&gt;  Sentry&lt;/li&gt;
&lt;li&gt;  Instabug&lt;/li&gt;
&lt;li&gt;  Datadog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fast rollback:&lt;/p&gt;

&lt;p&gt;keep the previous version ready and the ability to disable features remotely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipeline mobile best practice
&lt;/h2&gt;

&lt;p&gt;Automation of the release process (CI/CD) is a key practice in modern mobile development. It enables automatic building, testing, and deployment of iOS and Android apps, reducing errors and accelerating release times.&lt;/p&gt;

&lt;p&gt;Among the most common services we recommend there are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;GitHub Actions&lt;/strong&gt;: integrated CI/CD within GitHub, highly flexible. Supports Android/iOS builds with YAML workflows.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Bitrise:&lt;/strong&gt; mobile-specialized CI/CD platform, featuring a visual UI and support for Flutter, React Native, Kotlin, Swift.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Among the commonly used support tools for mobile release, we have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Fastlane&lt;/li&gt;
&lt;li&gt;  Gradle&lt;/li&gt;
&lt;li&gt;  Xcodebuild&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;To wrap up, we have explored mobile best practices around UI design, data management, and the release pipeline. Together, these areas provide the foundation for developing applications that are solid, modular, and maintainable throughout their entire lifecycle.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>android</category>
      <category>uidesign</category>
      <category>database</category>
    </item>
    <item>
      <title>Build Your MCP Server in Just 5 Minutes using Vibe Coding with Kiro</title>
      <dc:creator>Gianluca La Manna</dc:creator>
      <pubDate>Sat, 06 Sep 2025 13:06:41 +0000</pubDate>
      <link>https://dev.to/claranet/build-your-mcp-server-in-just-5-minutes-using-vibe-coding-with-kiro-2ech</link>
      <guid>https://dev.to/claranet/build-your-mcp-server-in-just-5-minutes-using-vibe-coding-with-kiro-2ech</guid>
      <description>&lt;p&gt;Hey folks, today I want to show you how to create an MCP server with special assistants: Kiro and Sonnet Claude. ✨&lt;/p&gt;

&lt;p&gt;But what is this new term? &lt;strong&gt;MCP&lt;/strong&gt;. Is it a buzzword? I don't know, but recently it is has been very discussed recently.&lt;/p&gt;

&lt;p&gt;So, let's dive into the MCP concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP: a new protocol by Anthropic
&lt;/h2&gt;

&lt;p&gt;I'll start by showing right away the schema of the MCP Protocol:&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%2Fpz79el6uo6t2f89fqabh.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%2Fpz79el6uo6t2f89fqabh.png" alt=" " width="777" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simple: with this protocol, we can connect our AI applications to the world.&lt;/p&gt;

&lt;p&gt;We can imagine this protocol like a USB port to connect the LLM to other services, like Gmail, Notion, Obsidian, Drive or more simply a DB or API service, with a unique standard. This is the work done by Anthropic.&lt;/p&gt;

&lt;p&gt;Now let's zoom in on this diagram 🔭&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%2Fufkcmzuq1hq3kpsd86ia.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%2Fufkcmzuq1hq3kpsd86ia.png" alt=" " width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the MCP is a layer that simplifies the communication between LLM and another service.&lt;/p&gt;

&lt;h2&gt;
  
  
  We define a real scenario.
&lt;/h2&gt;

&lt;p&gt;In this last year, I've focused on my diet and gym results. So I want to know what I eat and the nutrients in food.&lt;/p&gt;

&lt;p&gt;There are a ton of mobile applications to search for foods and get more info about them, but I'd like to search with more flexibility using natural language, for example, in a specific dataset when I'm using an AI client like Claude. The MCP protocol is the right way. We can ask, for example:&lt;br&gt;
"I ate two eggs Bio Carrefour", and I'll expect a response with nutritional information.&lt;br&gt;
Great, but how?&lt;/p&gt;

&lt;p&gt;Let's move on to practice.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use Vibe coding to create our MCP Server
&lt;/h2&gt;

&lt;p&gt;As the literature says, we have to use the code vibe formula&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$Vibe = (Project Soul + Your Intuition + Model's Character)$
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are curious, read &lt;a href="https://www.amazon.it/Vibe-Coding-Formula-Programmers-Programming/dp/B0FCRXZ4J2" rel="noopener noreferrer"&gt;this book&lt;/a&gt; by David Gillette.&lt;/p&gt;

&lt;p&gt;The first argument is &lt;em&gt;What&lt;/em&gt; and &lt;em&gt;Why&lt;/em&gt; of our project.&lt;/p&gt;

&lt;p&gt;The second is our unique contribution as a human creators. It's our gut feeling, our creative spark, our accumulated experience.&lt;/p&gt;

&lt;p&gt;The third is about understanding the specific AI model we are working with.&lt;/p&gt;

&lt;p&gt;With this information, we can use Kiro's agent to address it to create our MCP Server.&lt;/p&gt;

&lt;p&gt;Here is an example of text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1) Project Soul — What &amp;amp; Why

Goal: build an MCP Server that communicates with the dataset and APIs of Open Food Facts. The server should receive requests from an MCP Client and fetch food-related information directly from the official API (ingredients, nutrition facts, allergens, categories, brands), never generating or hallucinating data.

Why: this enables AI systems to integrate verifiable, real-world food data in a reliable and traceable way.

Expected outcome: an MCP implementation with well-defined tools that can search, filter, and retrieve products, always returning source: "openfoodfacts:&amp;lt;endpoint&amp;gt;".



2) Your Intuition — Human Spark

Keep the architecture clean and modular: separate the MCP protocol layer from the connectors to Open Food Facts.

Define strict JSON Schemas for inputs and outputs of all tools so Claude Sonnet can safely orchestrate the calls.

Add support for language localisation (lang), since Open Food Facts is multilingual.

Implement lightweight caching to avoid redundant API requests.

Provide clear error messages, always including a hint field to guide the client in correcting invalid inputs.

Code style requirement:

Do not use class constructors.

Use const declarations and arrow functions for all functions, exports, and callbacks.

Prefer functional composition over OOP patterns.

Use Typescript for entire project.



3) Model’s Character — Who You Are

Model to use: Claude Sonnet.

Character traits:

excels at producing structured, logical, and safe outputs;

prefers explicit schemas and typed definitions;

skilled at summarising without losing precision;

acts as a connector to the API, not as a data source.

Constraint: every output must reference the Open Food Facts source (source).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use this prompt on Kiro, and then we will have our MCP Server that gets the information from Open Food Facts via API (in this case, not authenticated)&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%2Fo9pgeqh5lq6f15e9b03r.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%2Fo9pgeqh5lq6f15e9b03r.png" alt="Kiro's screen with MCP Server" width="800" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Client MCP
&lt;/h2&gt;

&lt;p&gt;Now we need the client MCP to communicate with the Server.&lt;br&gt;
We have to create a &lt;code&gt;.kiro&lt;/code&gt; folder in our project and inside define a file called &lt;code&gt;mcp.json&lt;/code&gt; with this content&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&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;span class="nl"&gt;"calormeal"&lt;/span&gt;&lt;span class="p"&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;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/Users/myUser/projects/new-calormeal/build/index.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"disabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"autoApprove"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"search_products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_by_nutrition"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_by_category"&lt;/span&gt;&lt;span class="p"&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;span class="p"&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;p&gt;That's all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's try
&lt;/h2&gt;

&lt;p&gt;Now we can ask our server something, like this&lt;/p&gt;

&lt;p&gt;&lt;code&gt;I ate 2 organic eggs from Carrefour. How much protein did I consume?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the result&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%2F750ky5m78xa2ke8ct9r1.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%2F750ky5m78xa2ke8ct9r1.png" alt="Response from MCP Server" width="408" height="903"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the response does not come from Claude's model, but our server is called, which in turn calls the Open Food Facts API and returns the information according to the structure we have defined.&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;Let's see the code generated&lt;/p&gt;

&lt;p&gt;We have an &lt;code&gt;openfoodfacts.ts&lt;/code&gt; file that defines a direct interface with the openfoodfacts API.&lt;br&gt;
We have for example, the &lt;code&gt;searchProduct&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchProducts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SearchProductsInput&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductListResponse&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ErrorResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`search:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getCached&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ProductListResponse&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;cacheKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;search_terms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;page_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page_size&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sort_by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sort_by&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;popularity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.openfoodfacts.org/cgi/search.pl?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`API request failed with status &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Check your network connection and try again with a simpler query&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProductListResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;products&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;normalizeProduct&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;page_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;page_size&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openfoodfacts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nf"&gt;setCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Network error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unknown error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Verify your internet connection and ensure the query contains valid characters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;server.ts&lt;/code&gt; defines an MCP server, and there are 4 registered tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;search_products - General search by name/brand&lt;/li&gt;
&lt;li&gt;get_product - Product details via barcode&lt;/li&gt;
&lt;li&gt;search_by_nutrition - Filter by nutritional values&lt;/li&gt;
&lt;li&gt;search_by_category - Search by food category&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and then&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ListToolsRequest - Returns a list of available tools&lt;/li&gt;
&lt;li&gt;CallToolRequest - Runs the requested tool with input validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here we define the Server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&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="s1"&gt;@modelcontextprotocol/sdk/server/index.js&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;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;openfoodfacts-mcp-server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;tools&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then we define the tools for each action like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tools&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_products&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search for food products by name, brand, or keywords in Open Food Facts database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search query (product name, brand, keywords)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;minLength&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Language code (en, fr, es, de, etc.)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Page number for pagination&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;page_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Number of results per page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;sort_by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;enum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;product_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;popularity&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;created_t&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sort results by field&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;popularity&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;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="cm"&gt;/* [other tools] */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the setRequestHandler associates a handler function with a specific request type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pattern matching – When a request matches the schema, the function is executed&lt;/li&gt;
&lt;li&gt;Two registered handlers:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ListToolsRequestSchema → returns the list of available tools&lt;br&gt;
CallToolRequestSchema → executes a specific tool&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ListToolsRequestSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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;tools&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CallToolRequestSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_products&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;SearchProductsInputSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;searchProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;content&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&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="p"&gt;...&lt;/span&gt;
 &lt;span class="cm"&gt;/* [other cases] */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and finally run the server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;runServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StdioServerTransport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Open Food Facts MCP Server running on stdio&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use Claude Desktop
&lt;/h2&gt;

&lt;p&gt;Also, you can use the Claude desktop. Just configure this file &lt;code&gt;claude_desktop_config.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then run the application, and under settings, you can find the MCP&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%2Fpkax78zu0ri3c0f6nsd2.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%2Fpkax78zu0ri3c0f6nsd2.png" alt="MCP on Claude" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and the ours functions&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%2F5smqo5e0p7t8gb1cdpgw.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%2F5smqo5e0p7t8gb1cdpgw.png" alt="MCP functions" width="420" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result is&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%2F82vtczjc1qhrrloidwnh.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%2F82vtczjc1qhrrloidwnh.png" alt=" " width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find all the code on &lt;a href="https://github.com/thecoder93/calormeal-mcp" rel="noopener noreferrer"&gt;my repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Remeber&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find a lot of servers &lt;a href="https://github.com/modelcontextprotocol/servers" rel="noopener noreferrer"&gt;here&lt;/a&gt; (official and unofficial), but if you want to create one from zero to integrate your private service or for another reason, you can follow the previous steps for a good starter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks for the reading, and see you soon 👋🏻.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>mcp</category>
      <category>llm</category>
      <category>development</category>
    </item>
    <item>
      <title>Modernizing a large multi-team application with Micro Frontends</title>
      <dc:creator>Leonardo Montini</dc:creator>
      <pubDate>Fri, 27 Jun 2025 13:32:49 +0000</pubDate>
      <link>https://dev.to/claranet/modernizing-a-large-multi-team-application-with-micro-frontends-36dm</link>
      <guid>https://dev.to/claranet/modernizing-a-large-multi-team-application-with-micro-frontends-36dm</guid>
      <description>&lt;p&gt;Here’s a quite common scenario: you have a web application, built years ago, with deeply intertwined modules and dependencies. To make things worse, there are layers of legacy code built on top of each other, and multiple teams are dealing with the same codebase daily.&lt;/p&gt;

&lt;p&gt;Each team struggles to implement new features without stepping on each other’s toes, app-wide updates are a long and dangerous process and updating only a portion is just adding one more layer of tech debt and inconsistencies.&lt;/p&gt;

&lt;p&gt;The result? Slower development cycles, frustrated developers, and a product that struggles to keep up with user expectations and the market in general.&lt;/p&gt;

&lt;p&gt;One of our clients has been in a similar situation, here’s how we’re taking care of that with Micro Frontends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modernizing with Micro Frontends
&lt;/h2&gt;

&lt;p&gt;The main React application has almost 10 years and is bundled with an old version of Webpack while the new micro frontends are React apps running on Vite.&lt;/p&gt;

&lt;p&gt;The approach is to gradually extract smaller applications from the old system, using the long-time domain and project knowledge to properly know where to set the boundaries.&lt;/p&gt;

&lt;p&gt;Each smaller project has a unique goal in the system and is assigned to a dedicated and autonomous team. This brings a lot of advantages as each team can independently develop, deploy, and maintain their own portion of the system.&lt;/p&gt;

&lt;p&gt;Communication between the systems is mostly through custom events.&lt;/p&gt;

&lt;p&gt;With that in place, micro frontends enable incremental upgrades, allowing the legacy codebase to coexist with the new technologies. The teams can replace old modules one by one rather than rewriting the entire application all at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downsides you better not ignore
&lt;/h2&gt;

&lt;p&gt;Before going all-in into your next huge refactor to adopt micro frontends, there are some downsides you must understand.&lt;/p&gt;

&lt;p&gt;To begin with, to reduce complexity of your old legacy system you’re going to adopt an architecture that for sure fixes some of the flaws but also brings some more complexity in other areas of your application. To name a few, passing data between components of a single app might be trivial nowadays but sharing the state and communicating between micro frontends might not be that obvious. There’s plenty of solutions, but the team must get used to them.&lt;/p&gt;

&lt;p&gt;Separating all the moving parts might seem a simplification but now you must handle each one of them independently, including deployment and versioning. It’s an aspect you might see as a benefit, but it undeniably adds complexity.&lt;/p&gt;

&lt;p&gt;Consistency can also be a challenge if not handled properly, as autonomous teams can easily drift and lose sight of the bigger picture. A common outcome can be large differences in UI components giving an unpolished look at the final product.&lt;/p&gt;

&lt;h2&gt;
  
  
  DOs and DON’Ts
&lt;/h2&gt;

&lt;p&gt;A few tips to guide your implementation to maximise the benefits and avoiding some common mistakes. Some of these are common sense, some we banged our heads on during the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  DOs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Do define clear boundaries for each micro frontend&lt;/strong&gt;&lt;br&gt;
We all should have learned the lesson from microservices, using the wrong criteria to break down the monolith and set boundaries will inevitably do more harm than good. Make sure each micro frontend represents a distinct feature or domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Do ensure independent deployment&lt;/strong&gt;&lt;br&gt;
Micro frontends should be deployable independently. If you end up in the situation where you consistently can no longer deploy one sub-system by itself, you’re coupling too much and losing the benefits of having separate frontends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Do use shared libraries&lt;/strong&gt;&lt;br&gt;
Leverage shared libraries for common functionality like design systems, authentication, or API clients to reduce duplication of logic and inconsistencies. Module federation easily allows setting up shared libraries, use it.&lt;br&gt;
This should also help in making sure the user experience remains consistent through a centralized design system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Do start small&lt;/strong&gt;&lt;br&gt;
Begin with a single feature or module to test the waters. Gradually expand the micro frontend architecture as you gain confidence and refine your processes.&lt;br&gt;
If you’re transitioning from an old and large system this is even more relevant to avoid unexpected issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  DON'Ts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Don’t overcomplicate your architecture&lt;/strong&gt;&lt;br&gt;
Once you unlock the power of splitting into separate apps you might enjoy it too much. You can’t look at micro frontends as if they were simple folders in your monolithic app. Splitting and organizing components into separate folders is as easy as (auto) updating the imports, doing the same over many micro frontends can be way more painful.&lt;br&gt;
Avoid immediately splitting your application into too many micro frontends without a strong rationale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Don’t ignore cross-team collaboration&lt;/strong&gt;&lt;br&gt;
While micro frontends promote autonomy, teams must still collaborate to ensure consistency and avoid duplication. Regular communication and alignment are essential. Some code and logic will be duplicated, that’s fine, just make sure it’s intentional and under control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Don’t use different frameworks for the sake of it&lt;/strong&gt;&lt;br&gt;
Although micro frontends allow flexibility in technology choices, using entirely different frameworks (React for a module and Angular for another) can complicate integration and increase onboarding time for new developers.&lt;br&gt;
Just because you can doesn’t mean you should.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Don’t forget testing&lt;/strong&gt;&lt;br&gt;
Each micro frontend must be thoroughly tested both independently and as part of the larger application. Skipping integration tests can result in unexpected issues when modules interact with each other.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Don’t forget about versioning&lt;/strong&gt;&lt;br&gt;
Proper version control is critical for shared libraries and APIs used across micro frontends. Ensure backward compatibility to avoid breaking changes that disrupt other modules. If you end up having breaking changes all the time, maybe moving over to micro frontend wasn’t the right choice (or you’re doing it wrong!)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Don’t skip documentation&lt;/strong&gt;&lt;br&gt;
Document the architecture, module boundaries, communication protocols, and deployment processes thoroughly. This ensures smooth onboarding for new developers and reduces confusion over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Micro frontends are indeed an interesting and valuable architecture bringing several benefits, as in our case it allowed us to gradually upgrade the system without the risks of a full rewrite by keeping the teams almost independent from each other.&lt;/p&gt;

&lt;p&gt;However, it’s worth mentioning that it’s not always the best solution and it should be considered only if some conditions are met (application size, team(s) size, technical complexity, etc...). Smaller applications or teams may not benefit from the added overhead of managing multiple micro frontends, and simpler architectures might suffice for less complex systems.&lt;/p&gt;

&lt;p&gt;This architecture doesn’t magically get rid of complexity, but it shifts it to other places trying to make it more manageable. If you and your team are not ready to manage that new kind of complexity, think again if this is really what you’re looking for.&lt;/p&gt;

&lt;p&gt;As always, bad adoption of good practices can do more harm than good, do your research thoroughly and if you think you’ve got what it takes, then go for it and enjoy the flexibility of micro frontends!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>development</category>
    </item>
    <item>
      <title>Modern MVC with HTMX</title>
      <dc:creator>Paolo Rabbito</dc:creator>
      <pubDate>Fri, 06 Jun 2025 15:05:35 +0000</pubDate>
      <link>https://dev.to/claranet/modern-mvc-with-htmx-3a7f</link>
      <guid>https://dev.to/claranet/modern-mvc-with-htmx-3a7f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;“We need an admin panel that’s only accessible to administrators, not regular users.”&lt;br&gt;
“I’d like a dashboard where I can track certain key metrics.”&lt;br&gt;
“It would be great to have a web page where, as an admin, I can upload articles or manage users.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’ve ever worked on an e-commerce platform, a CRM, or similar projects, chances are you’ve heard requests like these. Usually, they’re followed by something like: “It doesn’t have to be too complex—after all, regular users won’t see it.”&lt;/p&gt;

&lt;h1&gt;Issues with Traditional Approaches&lt;/h1&gt;

&lt;p&gt;To build our application, we could choose a tool like Angular or React. Alternatively, if we’re working with a backend framework such as Django or Symfony, we might opt for a template engine combined with some simple JavaScript.&lt;/p&gt;

&lt;p&gt;However, both of these approaches have their drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Using tools like Angular or React requires additional knowledge, more time to start up, introduces extra dependencies that need to be maintained and updated, and ultimately adds unnecessary complexity to the project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Relying on HTML with a template engine and vanilla JavaScript is simpler in theory, but no one enjoys dealing with long stretches of JavaScript just to handle basic interactions that most libraries can take care of effortlessly nowadays.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And what if our frontend team is overloaded, and this task needs to be handled by someone who’s not comfortable with those technologies?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s where HTMX might be exactly what we need!&lt;/p&gt;

&lt;h1&gt;What's HTMX&lt;/h1&gt;

&lt;p&gt;From the &lt;a href="https://htmx.org/docs/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; we can read that: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"htmx is a library that allows you to access modern browser features directly from HTML, rather than using javascript."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;HTMX's tag-like attributes simplify interaction with the backend while keeping the logic in the HTML layer. This makes development more intuitive and reduces JavaScript complexity in many scenarios.&lt;/p&gt;

&lt;p&gt;When applied to our use case, HTMX offers several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since we only need to write HTML, our code is cleaner, more understandable, and easier to maintain.&lt;/li&gt;
&lt;li&gt;The absence of JavaScript and related libraries makes it more accessible for backend developers, and reduces ongoing maintenance requirements.&lt;/li&gt;
&lt;li&gt;Development is faster, as HTMX takes care of most of the necessary logic for us.&lt;/li&gt;
&lt;/ul&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%2Frmm1t0ayaq70ze7pm9mr.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%2Frmm1t0ayaq70ze7pm9mr.png" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;The Simplicity of HTMX&lt;/h1&gt;

&lt;p&gt;HTMX provides us with several useful tools for making AJAX calls, replacing parts of HTML with the received responses, triggering requests on certain events, and much more.&lt;/p&gt;

&lt;p&gt;HTMX makes simplicity its greatest strength for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is so easy to integrate into your projects.&lt;/li&gt;
&lt;li&gt;It doesn't come with heavy dependencies, doesn’t require TypeScript, nor does it rely on ES6. This makes it perfect for browser-based applications and even compatible with Internet Explorer 11.&lt;/li&gt;
&lt;li&gt;Its lack of dependencies and the straightforward way HTMX’s code is designed make it ideal for the open-source world, encouraging user contributions and collaboration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;How to start an HTMX project&lt;/h4&gt;

&lt;p&gt;HTMX is a dependency-free, browser-oriented javascript library. To use it we can simply add a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag to our document head and we are ready to go.&lt;/p&gt;

&lt;p&gt;We can include HTMX via CDN:&lt;br&gt;
&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;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Modern MVC with HTMX&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script 
   &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/htmx.org@2.0.4"&lt;/span&gt; &lt;span class="na"&gt;integrity=&lt;/span&gt;&lt;span class="s"&gt;"sha384-HGfztofotfshcF7+8n44JQL2oJmowVChPTg48S+jvZoztPfvwD79OC/LTtG6dMp+"&lt;/span&gt; &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or we can download from &lt;a href="https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js" rel="noopener noreferrer"&gt;here&lt;/a&gt; and include the file in our HTML:&lt;br&gt;
&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;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Modern MVC with HTMX&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/path/to/htmx.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also install it in our application as an external dependency using our favorite package manager. This could be useful in case we want to extend a React application with HTMX.&lt;/p&gt;

&lt;p&gt;Installing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;htmx.org@2.0.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add import in our javascript/typescript 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="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;htmx.org&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this article we will use it via CDN.&lt;/p&gt;

&lt;h4&gt;AJAX Requests&lt;/h4&gt;

&lt;p&gt;HTMX provides a range of attributes to handle HTTP requests directly in HTML, with each one serving a specific purpose.&lt;/p&gt;

&lt;h6&gt;hx-get&lt;/h6&gt; 

&lt;p&gt;Can be used to send HTTP GET requests. It is typically employed to retrieve data from the server for display or interaction without requiring form submissions. When combined with hx-params, you can specify query parameters to dynamically modify the request. &lt;br&gt;
For example:&lt;br&gt;
&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;button&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/api/data"&lt;/span&gt; &lt;span class="na"&gt;hx-params=&lt;/span&gt;&lt;span class="s"&gt;"key=value"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Fetch Data&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends a GET request to /api/data with the parameter key=value.&lt;/p&gt;

&lt;h6&gt;hx-post,hx-put and hx-patch&lt;/h6&gt;

&lt;p&gt;These attributes send HTTP POST/PUT/PATCH requests, commonly used to submit data to the server, such as form inputs or payloads. This is ideal for operations that create or update resources. For example:&lt;br&gt;
&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;form&lt;/span&gt; &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/api/save"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above sends the form data to /api/save using a POST request but it can easily be changed with &lt;code&gt;hx-put&lt;/code&gt; or &lt;code&gt;hx-patch&lt;/code&gt;, depending on type of request we want to send.&lt;/p&gt;

&lt;h6&gt;hx-delete&lt;/h6&gt; 

&lt;p&gt;Can be used to send HTTP DELETE requests, intended for removing a resource from the server. Simple and effective, it works as shown below:&lt;br&gt;
&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;button&lt;/span&gt; &lt;span class="na"&gt;hx-delete=&lt;/span&gt;&lt;span class="s"&gt;"/api/delete"&lt;/span&gt; &lt;span class="na"&gt;hx-params=&lt;/span&gt;&lt;span class="s"&gt;"id=456"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Delete Resource&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends a DELETE request to remove the resource identified by id=456.&lt;/p&gt;

&lt;h4&gt;Triggering Requests&lt;/h4&gt;

&lt;p&gt;It’s possible to trigger requests with different events using the &lt;code&gt;hx-trigger&lt;/code&gt; attribute. By setting specific values for this attribute, you can control when a request is fired. Below are some examples of commonly used values for &lt;code&gt;hx-trigger&lt;/code&gt;:&lt;/p&gt;

&lt;h6&gt;input&lt;/h6&gt; 

&lt;p&gt;Fires the request on every keystroke, perfect for real-time updates (such as live search results).&lt;br&gt;
&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;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt; &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;change&lt;/h6&gt;

&lt;p&gt;Fires the request only when the element loses focus or when its value changes (great for dropdowns or form fields).&lt;br&gt;
&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;select&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/api/filter"&lt;/span&gt; &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"change"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"all"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;All&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"active"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Active&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"completed"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Completed&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/select&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;load&lt;/h6&gt; 

&lt;p&gt;automatically once the element is initially loaded onto the page. This is useful for dynamic content loading or initializing parts of a webpage.&lt;br&gt;
&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;div&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/api/data"&lt;/span&gt; &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"load"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;delay&lt;/h6&gt; 

&lt;p&gt;This value lets you delay the request by a specified amount of time after the triggering event. If another event of the same type occurs during the delay period, the countdown resets, ensuring only one request is sent after the delay. Could be useful in live search combined with other type of trigger.&lt;br&gt;
&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;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt; &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"input delay:500ms"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check all the possible use case of triggers you can check the &lt;a href="https://htmx.org/docs/#triggers" rel="noopener noreferrer"&gt;docs&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Handle Response&lt;/h4&gt;

&lt;p&gt;HTMX provides attributes such as hx-target and hx-swap to control how and where a server’s response is applied to the DOM. These attributes give you precise control over your page's dynamic behavior without requiring JavaScript.&lt;/p&gt;

&lt;h6&gt;hx-swap&lt;/h6&gt; 

&lt;p&gt;This attribute lets you define how the response content from the server is swapped into the target element (or the element that made the request). The default behavior is to replace the inner content of the targeted element using &lt;code&gt;innerHTML&lt;/code&gt;.&lt;br&gt;
&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;button&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/api/message"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get Message&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;outerHTML&lt;/code&gt;replaces the entire target element (including the tag itself) with the response.&lt;br&gt;
&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;div&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/api/card"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Fetch Card&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check every possible values read the &lt;a href="https://htmx.org/attributes/hx-swap/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;&lt;/p&gt;

&lt;h6&gt;hx-target&lt;/h6&gt; 

&lt;p&gt;This attribute allows you to specify which element in the DOM will be swapped with the server's response, rather than swapping the element that triggered the request.&lt;br&gt;
&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;button&lt;/span&gt; &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/api/message"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#output"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get Message&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"output"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server's response replaces the content of the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with &lt;code&gt;id="output"&lt;/code&gt; (using the default &lt;code&gt;innerHTML&lt;/code&gt; swap behavior).&lt;/p&gt;

&lt;h1&gt;Practical Use Cases of HTMX&lt;/h1&gt;

&lt;p&gt;Many dashboards share common features, such as pagination, real-time data polling to update charts, form validation for adding new users or other entities, bulk file uploads, and table search functionality. HTMX simplifies the implementation of all these tasks—and much more—making development faster and more streamlined.&lt;/p&gt;

&lt;p&gt;In this article, I’ll guide you through several practical examples to showcase HTMX's capabilities. However, I strongly recommend exploring the &lt;a href="https://htmx.org/docs/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; for a comprehensive overview of its features and use cases.&lt;/p&gt;

&lt;p&gt;The examples presented here are built using HTMX, Tailwind CSS, and Twig (the template engine used by the Symfony framework). That said, these examples can be easily adapted to work with any backend language or template engine.&lt;/p&gt;

&lt;h2&gt;Form Validation&lt;/h2&gt;

&lt;p&gt;HTMX can be used to implement real-time form validation by sending data to the server to check its validity and dynamically displaying error messages or confirmations. For this, you can use attributes like &lt;code&gt;hx-post&lt;/code&gt;, &lt;code&gt;hx-trigger&lt;/code&gt;, &lt;code&gt;hx-target&lt;/code&gt;, and &lt;code&gt;hx-swap&lt;/code&gt;.&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%2F0t5couj7bpkmyk5xanwd.gif" 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%2F0t5couj7bpkmyk5xanwd.gif" alt=" "&gt;&lt;/a&gt;&lt;br&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%2Fhiixobahkc1tz2xcjw4u.gif" 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%2Fhiixobahkc1tz2xcjw4u.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Controller:&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Route('/validate-email', name: 'validate_email', methods: ['POST'])]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;validateEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'email'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Mock validation logic (replace with your validation logic)&lt;/span&gt;
    &lt;span class="nv"&gt;$isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;filter_var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FILTER_VALIDATE_EMAIL&lt;/span&gt;&lt;span class="p"&gt;)&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="c1"&gt;// Return a user-friendly message formatted for display&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;span class="text-sm text-green-600"&amp;gt;Email is valid!&amp;lt;/span&amp;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;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;span class="text-sm text-red-600"&amp;gt;Please enter a valid email address.&amp;lt;/span&amp;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;h4&gt;FormHTML&lt;/h4&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;form&lt;/span&gt; &lt;span class="na"&gt;hx-post=&lt;/span&gt;&lt;span class="s"&gt;"/validate-email"&lt;/span&gt; &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#email-validation-result"&lt;/span&gt; &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML"&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;for=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block text-sm font-medium text-gray-700"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Email&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"border border-gray-300 px-3 py-2 rounded-md"&lt;/span&gt;
    &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"change delay:500ms"&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;id=&lt;/span&gt;&lt;span class="s"&gt;"email-validation-result"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-sm mt-2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;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;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-blue-500 text-white px-3 py-2 rounded hover:bg-blue-700"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;Active Searching&lt;/h2&gt;

&lt;p&gt;To implement active searching we need to use &lt;code&gt;hx-get&lt;/code&gt;to send get request, &lt;code&gt;hx-params&lt;/code&gt; to add query params to our request, &lt;code&gt;hx-target&lt;/code&gt; to point to our table that need to be populated with filtered result and &lt;code&gt;hx-trigger&lt;/code&gt; to define when and how the get request should be sent.&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%2F75mzq5wip7tdpzv2vxv4.gif" 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%2F75mzq5wip7tdpzv2vxv4.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Controller:&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Route('/users_search', name: 'users_search', methods: ['GET'])]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;MapQueryParameter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//return html file to frontend if is the first load&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'HX-Request'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users/search_user.html'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//how to filter result depends on your system&lt;/span&gt;
    &lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$search&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;//return table rows with filtered data&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&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;h4&gt;Building response:&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;buildResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$html&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="s1"&gt;'&amp;lt;tr&amp;gt;
         &amp;lt;td class="px-6 py-4 whitespace-nowrap"&amp;gt;
         &amp;lt;div class="text-sm text-blue-900"&amp;gt;'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;/div&amp;gt;
         &amp;lt;/td&amp;gt;
         &amp;lt;td class="px-6 py-4 whitespace-nowrap"&amp;gt;
         &amp;lt;div class="text-sm text-blue-900"&amp;gt;'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;/div&amp;gt;
         &amp;lt;/td&amp;gt;
         &amp;lt;td class="px-6 py-4 whitespace-nowrap"&amp;gt;
         &amp;lt;div class="text-sm text-blue-900"&amp;gt;'&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'last_name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;/div&amp;gt;
         &amp;lt;/td&amp;gt;
         &amp;lt;/tr&amp;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;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$html&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;h4&gt;search_user.html:&lt;/h4&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;!--....other html....--&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; 
&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form-control border border-gray-300 rounded-md px-3 py-2 mb-4"&lt;/span&gt; 
&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; 
&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Begin Typing To Search Users..."&lt;/span&gt;
&lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/users_search"&lt;/span&gt;
&lt;span class="na"&gt;hx-params=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt;
&lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"input changed delay:500ms, keyup[key=='Enter'], load"&lt;/span&gt;
&lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#search-results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!--....other html....--&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;tbody&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"search-results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;Polling&lt;/h2&gt;

&lt;p&gt;To implement a polling system we need to use &lt;code&gt;hx-get&lt;/code&gt;to send multiple get request, &lt;code&gt;hx-swap&lt;/code&gt; to update the html with the response and &lt;code&gt;hx-trigger&lt;/code&gt; to get data when we load the page and every "x" seconds.&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%2Fjltbgheicys21uvj8gvo.gif" 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%2Fjltbgheicys21uvj8gvo.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;Controller&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Route('/polling/data', name: 'polling_data', methods: ['GET'])]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;pollingData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$companies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;companyService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCompanyWithUpdate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;//return update about growth for each company&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;buildResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$companies&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;h4&gt;Build response:&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;buildResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$companies&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$companies&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$company&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$html&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="s1"&gt;'&amp;lt;tr &amp;gt; 
         &amp;lt;td class="px-6 py-4 whitespace-nowrap"&amp;gt;  
         &amp;lt;div class="text-sm text-blue-900"&amp;gt;'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$company&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;/div&amp;gt;
         &amp;lt;/td&amp;gt;
         &amp;lt;td class="px-6 py-4 whitespace-nowrap"&amp;gt;  
         &amp;lt;div class="text-sm text-blue-900"&amp;gt;'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$company&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'growth'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;/div&amp;gt;
         &amp;lt;/td&amp;gt;
         &amp;lt;/tr&amp;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;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$html&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;h4&gt;polling_table.html:&lt;/h4&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;!--...other html....--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;tbody&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-white divide-y divide-blue-100"&lt;/span&gt; 
       &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/polling/data"&lt;/span&gt; 
       &lt;span class="na"&gt;hx-trigger=&lt;/span&gt;&lt;span class="s"&gt;"load, every 3s"&lt;/span&gt; 
       &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"innerHTML"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!--...other html....--&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;Pagination&lt;/h2&gt;

&lt;p&gt;To implement pagination i'll show you a different approach using a template engine (Twig in this case).&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%2F4l1xio0fu6to4nsnfrn6.gif" 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%2F4l1xio0fu6to4nsnfrn6.gif" alt=" "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In these example we have used &lt;code&gt;hx-delete&lt;/code&gt; to send the delete request with the &lt;code&gt;hx-confirm&lt;/code&gt;,&lt;code&gt;hx-swap&lt;/code&gt;and &lt;code&gt;hx-target&lt;/code&gt; inside the tbody element.&lt;/p&gt;

&lt;p&gt;Other than delete we have used &lt;code&gt;hx-get&lt;/code&gt; combined with &lt;code&gt;hx-target&lt;/code&gt; and &lt;code&gt;hx-swap&lt;/code&gt;to implement next and prev button.&lt;/p&gt;

&lt;h4&gt;Controller:&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="na"&gt;#[Route('/articles/page', name: 'app_articles_page', methods: ['GET'])]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Response&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$articlesPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;articlesService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'page'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pageSize'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'articles/articles.html.twig'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'articles'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$articlesPage&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'currentPage'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$articlesPage&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'totalPages'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$articlesPage&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;totalPages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'nextPage'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$articlesPage&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;nextPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'previousPage'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$articlesPage&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;previousPage&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;h4&gt;Article's table:&lt;/h4&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;tbody&lt;/span&gt; &lt;span class="na"&gt;hx-confirm=&lt;/span&gt;&lt;span class="s"&gt;"Are you sure?"&lt;/span&gt; 
       &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"closest tr"&lt;/span&gt; 
       &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML swap:1s"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
{% for article in articles %}
&lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"px-6 py-4 whitespace-nowrap"&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;"text-sm text-blue-900"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ article.id }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"px-6 py-4 whitespace-nowrap"&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;"text-sm text-blue-900"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ article.title }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"px-6 py-4 whitespace-nowrap"&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;"text-sm text-blue-900"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ article.price }}&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"px-6 py-4 whitespace-nowrap"&lt;/span&gt;&lt;span class="nt"&gt;&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;"bg-red-500 hover:bg-red-700 text-white py-2 px-4     rounded"&lt;/span&gt; 
    &lt;span class="na"&gt;hx-delete=&lt;/span&gt;&lt;span class="s"&gt;"/articles/{{ article.id }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      Cancel
    &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
{% endfor %}
&lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;Article's button:&lt;/h4&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex justify-center mt-6 space-x-2"&lt;/span&gt;&lt;span class="nt"&gt;&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;"px-3 py-1 bg-blue-700 text-white rounded hover:bg-blue-800 disabled:opacity-50"&lt;/span&gt;
        &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/articles/page?page={{ previousPage }}"&lt;/span&gt;
        &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#articles-table-and-pagination"&lt;/span&gt;
        &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML"&lt;/span&gt;
&lt;span class="err"&gt;{%&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt; &lt;span class="na"&gt;previousPage&lt;/span&gt; &lt;span class="na"&gt;is&lt;/span&gt; &lt;span class="na"&gt;null&lt;/span&gt; &lt;span class="err"&gt;%}&lt;/span&gt;&lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="err"&gt;{%&lt;/span&gt; &lt;span class="na"&gt;endif&lt;/span&gt; &lt;span class="err"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Prev&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"px-3 py-1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
Pagina {{ currentPage }} di {{ totalPages }}
&lt;span class="nt"&gt;&amp;lt;/span&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;"px-3 py-1 bg-blue-700 text-white rounded hover:bg-blue-800 disabled:opacity-50"&lt;/span&gt;
        &lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;"/articles/page?page={{ nextPage }}"&lt;/span&gt;
        &lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;"#articles-table-and-pagination"&lt;/span&gt;
        &lt;span class="na"&gt;hx-swap=&lt;/span&gt;&lt;span class="s"&gt;"outerHTML"&lt;/span&gt;
&lt;span class="err"&gt;{%&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt; &lt;span class="na"&gt;nextPage&lt;/span&gt; &lt;span class="na"&gt;is&lt;/span&gt; &lt;span class="na"&gt;null&lt;/span&gt; &lt;span class="err"&gt;%}&lt;/span&gt;&lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="err"&gt;{%&lt;/span&gt; &lt;span class="na"&gt;endif&lt;/span&gt; &lt;span class="err"&gt;%}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Implementing features like active searching, and many others, becomes remarkably simple with HTMX, requiring you to write almost exclusively HTML. This simplicity reduces development complexity while maintaining powerful functionality for dynamic, interactive web pages.&lt;/p&gt;

&lt;p&gt;HTMX is an excellent choice for projects where advanced graphical functionality isn’t a priority, such as administration panels, dashboards, or other content-focused applications. By eliminating the need for extensive JavaScript frameworks, HTMX helps cut development costs and speeds up the delivery process, all while keeping your codebase easier to maintain.&lt;/p&gt;

&lt;p&gt;Moreover, HTMX bridges the gap for backend-oriented developers, empowering them to create dynamic frontend features without requiring deep knowledge of modern JavaScript tooling. Its lightweight, dependency-free nature makes it not only cost-effective but also accessible to a wider range of programmers.&lt;/p&gt;

&lt;p&gt;Whether you're building practical dashboards, simplifying server-client interactions, or just striving for cleaner code, HTMX provides the flexibility and efficiency to meet your goals. Combined with its compatibility across various template engines and backend languages, HTMX becomes a versatile and indispensable tool for modern web development.&lt;/p&gt;

&lt;p&gt;If you'd like to dive deeper into practical examples, you can find the repository &lt;a href="https://github.com/claranet-it/devrel-mvc-with-HTMX" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>htmx</category>
      <category>development</category>
      <category>programming</category>
    </item>
    <item>
      <title>Empower Your Development: Simulating AWS with LocalStack for Efficient Local Testing</title>
      <dc:creator>Massimo Biagioli</dc:creator>
      <pubDate>Mon, 26 May 2025 12:38:42 +0000</pubDate>
      <link>https://dev.to/claranet/empower-your-development-simulating-aws-with-localstack-for-efficient-local-testing-3n6</link>
      <guid>https://dev.to/claranet/empower-your-development-simulating-aws-with-localstack-for-efficient-local-testing-3n6</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In the development of cloud-based applications, the ability to replicate AWS services on local environments is invaluable, saving time and resources during the testing phase. LocalStack provides a comprehensive solution by emulating a wide range of AWS services locally, enabling developers to test their cloud applications without incurring the costs and complexities associated with connecting to actual AWS services. This robust tool supports services such as Lambda, S3, DynamoDB, and many more, offering a seamless integration with your existing AWS workflows. In this exploration, we will discuss how LocalStack can help developers and teams streamline their development process by providing a reliable and scalable local testing environment. Learn how to set up your LocalStack, integrate with your development pipeline, and leverage this powerful tool to enhance productivity, reduce development costs, and accelerate your go-to-market strategy. Embrace the power of local emulation with LocalStack and transform your cloud application development lifecycle. &lt;/p&gt;

&lt;h2&gt;
  
  
  Navigating the Complexity of Cloud Development
&lt;/h2&gt;

&lt;p&gt;Cloud development presents a multifaceted challenge that significantly differs from traditional web development. Unlike monolithic web applications, which can often be built and tested in a single environment, cloud applications are inherently distributed, relying on a diverse array of services that interact with each other in complex ways. This architecture introduces additional layers of complexity, including service orchestration, network configurations, and data management across multiple cloud services. Moreover, the dynamic nature of the cloud environment necessitates considerations for scalability, latency, and security that are rarely required in conventional applications. Developers must navigate intricate dependencies and ensure that their applications remain resilient and performant under varying conditions. Understanding these complexities is crucial in adopting effective strategies and tools, such as LocalStack, that simplify local testing and streamline development workflows. Embracing these challenges is key to leveraging the full potential of cloud-native applications while mitigating risks associated with deployment and integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case: Managing a New Booking in a Cloud-Based Booking System
&lt;/h2&gt;

&lt;p&gt;Consider a cloud-based booking system where managing a new reservation is a key function. When a customer makes a new booking, the process involves several important steps supported by various AWS services. First, the booking details are saved in DynamoDB, which offers a scalable and easy-to-use NoSQL database for storing and accessing reservation information. At the same time, the system creates a confirmation PDF receipt to verify the booking, ensuring customers have a clear record of their reservation. This receipt is then stored in an S3 bucket, utilizing AWS's object storage capabilities for durability and easy access. By using these services, the platform ensures efficient data management and provides a smooth user experience. Implementing LocalStack allows developers to simulate this entire process locally, helping them test and improve each component —ultimately saving time and reducing costs while ensuring strong functionality before deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  A First Approach: Leveraging a Real AWS Environment
&lt;/h2&gt;

&lt;p&gt;Testing in a real AWS environment can provide a valuable perspective on how cloud applications will perform in production. The primary advantage of this approach is: &lt;/p&gt;

&lt;p&gt;Accurate Insights: Provides a true representation of service behavior, performance, and interactions within the full AWS ecosystem, allowing for the identification of potential integration issues. &lt;/p&gt;

&lt;p&gt;However, relying solely on a real AWS environment for testing comes with notable drawbacks: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost&lt;/strong&gt;: The expenses related to running resources in AWS can quickly accumulate, especially during extensive testing phases or with suboptimal resource management. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complexity&lt;/strong&gt;: Managing AWS environments can lead to longer setup and teardown times, making it challenging to iterate quickly on development and testing cycles. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unpredictable Issues&lt;/strong&gt;: External factors such as throttling limits, network latency, or availability concerns may arise in the shared environment, potentially distorting test results and making it difficult to consistently replicate scenarios. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consequently, while using a real AWS environment has its merits, it is important to supplement this approach with localized testing solutions to enhance efficiency and control in the development process. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing LocalStack: Empowering Local Development
&lt;/h2&gt;

&lt;p&gt;LocalStack is an open-source tool that emulates Amazon Web Services (AWS) on your local machine, enabling developers to build, test, and deploy cloud applications without incurring the costs and complexities associated with actual cloud services. By providing a full-fledged local environment that mimics the behavior of AWS services, LocalStack supports a wide range of functionalities including Lambda, S3, DynamoDB, and many others. &lt;/p&gt;

&lt;p&gt;The primary benefit of using LocalStack in the development lifecycle is the significant enhancement it brings to the feedback loop. Developers can quickly prototype and test new features in a controlled setting, leading to rapid iterations without the delays associated with deploying to the cloud. This accelerated feedback allows teams to identify and fix issues early in the development process, reducing the likelihood of regressions and enhancing the overall quality of releases. &lt;/p&gt;

&lt;p&gt;Moreover, by integrating LocalStack into your development pipeline, you can simulate realistic scenarios that closely mirror production environments. This ensures that code changes are thoroughly tested before deployment, leading to more reliable applications and smoother rollouts. As a result, LocalStack not only streamlines development workflows but also fosters a culture of quality and accountability, allowing teams to deliver robust cloud-native applications with confidence. &lt;/p&gt;

&lt;p&gt;You can easily run LocalStack using Docker, making it even more accessible for development teams. Here’s a simple example of a docker-compose.yml file to get you started:&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
  &lt;span class="na"&gt;localstack&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="na"&gt;container_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;${LOCALSTACK_DOCKER_NAME:-localstack-main}"&lt;/span&gt; 
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localstack/localstack&lt;/span&gt; 
    &lt;span class="na"&gt;ports&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;127.0.0.1:4566:4566"&lt;/span&gt;            &lt;span class="c1"&gt;# LocalStack Gateway &lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:4510-4559:4510-4559"&lt;/span&gt;  &lt;span class="c1"&gt;# external services port range &lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DEBUG=${DEBUG:-1}&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LS_LOG=info&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;LOCALSTACK_HOST=localstack&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;HOSTNAME=localstack&lt;/span&gt; 
    &lt;span class="na"&gt;volumes&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;${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Structuring the Web Application: A Lambda-Based Architecture
&lt;/h2&gt;

&lt;p&gt;Our web application follows a modern design pattern known as a "lambdalith," where we use AWS Lambda functions to create a scalable and cohesive application built with Python and FastAPI. This approach allows us to minimize the need for infrastructure management while maximizing scalability and responsiveness. &lt;/p&gt;

&lt;p&gt;The application's architecture will include the following key components when deployed on AWS: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Gateway&lt;/strong&gt;: This acts as the entry point for incoming requests. API Gateway makes our FastAPI application accessible as RESTful endpoints, handling request routing, authentication, and response formatting. It ensures efficient and secure communication between clients and our backend functions. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lambda Layer&lt;/strong&gt;: To manage dependencies efficiently, we use Lambda Layers. This feature allows us to package shared libraries or code that can be used across multiple Lambda functions. By separating the core application logic from its dependencies, we can optimize deployment times and keep our functions lightweight. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lambda Function&lt;/strong&gt;: The core of our application is in the Lambda functions, which run the business logic defined using FastAPI. For this example, we use Mangum, a wrapper that transforms a FastAPI application into a Lambda-compatible function. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By structuring our web application in this way, we can take full advantage of serverless technologies while keeping our codebase maintainable and organized.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt; 

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt; 
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi.middleware.cors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt; 
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mangum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Mangum&lt;/span&gt; 

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.routers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;booking&lt;/span&gt; 


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&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="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include_router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;health&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include_router&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;booking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/booking&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;booking&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 


&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Mangum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deciding What to Include in LocalStack: Focus on External Dependencies
&lt;/h2&gt;

&lt;p&gt;When working with LocalStack, it's important to determine which components of your application to simulate locally. Since Mangum acts as a wrapper to transform a FastAPI application into a Lambda-compatible function, we can simplify our setup by focusing on external dependencies, such as S3 or DynamoDB, rather than trying to simulate the entire Lambda and API Gateway stack. &lt;/p&gt;

&lt;p&gt;In this example, we chose the second approach. Here are three key advantages of this choice: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplified Development&lt;/strong&gt;: By only simulating the essential AWS services that our application interacts with, we reduce complexity. This makes it easier for developers to focus on building and testing core functionality without getting sidetracked by configuring Lambda or API Gateway in a local environment. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faster Feedback Loop&lt;/strong&gt;: Concentrating on external dependencies allows for quicker testing and debugging. With LocalStack running only the necessary services, developers can rapidly iterate on their application, receiving immediate feedback and enhancing productivity. This streamlined approach accelerates development cycles. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficient Resource Usage&lt;/strong&gt;: By limiting the number of resources that need to be simulated, we can run tests with a lighter environment. This makes it easier to manage local resources and keeps the testing setup straightforward, allowing developers to focus more on code quality and less on infrastructure concerns. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By focusing our LocalStack setup on external dependencies, we maintain an efficient local testing environment that supports development efforts while relying on Mangum to handle the conversion of our FastAPI application into a Lambda function. &lt;/p&gt;

&lt;p&gt;Below is the Terraform code for creating the necessary S3 bucket and DynamoDB table: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;s3.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"booking_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"booking"&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;dynamodb.tf&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_dynamodb_table"&lt;/span&gt; &lt;span class="s2"&gt;"booking_table"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;name&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"booking"&lt;/span&gt; 
  &lt;span class="nx"&gt;billing_mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PAY_PER_REQUEST"&lt;/span&gt; 
  &lt;span class="nx"&gt;hash_key&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"customer_name"&lt;/span&gt; 
  &lt;span class="nx"&gt;range_key&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"check_in"&lt;/span&gt; 

  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"customer_name"&lt;/span&gt; 
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S"&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt; 

  &lt;span class="nx"&gt;attribute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"check_in"&lt;/span&gt; 
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S"&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;h2&gt;
  
  
  Use Case: Create Booking
&lt;/h2&gt;

&lt;p&gt;When a customer creates a new booking, the application needs to seamlessly store the booking details and generate a confirmation receipt. To achieve this, we use the same library, Boto3, to interact with both S3 and DynamoDB when using LocalStack and when working with real AWS services. This creates a "transparent" development experience, as the code remains largely unchanged between local and production environments; developers simply need to adjust the connection parameters. &lt;/p&gt;

&lt;p&gt;Here's a step-by-step breakdown of how the process works: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Storing Booking Details in DynamoDB&lt;/strong&gt;: When a booking is created, the application saves the booking information—such as booking ID, customer details, and reservation dates—in a DynamoDB table. Using Boto3, the same code can connect to either LocalStack or the actual DynamoDB service in AWS by changing the endpoint URL. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generating a Confirmation PDF&lt;/strong&gt;&lt;br&gt;
: After the booking details are saved, the system generates a PDF receipt confirming the booking. This receipt is then stored in an S3 bucket, again utilizing Boto3 to handle the upload. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Storing the Receipt in S3&lt;/strong&gt;: The receipt is saved to an S3 bucket, providing customers with a downloadable file as proof of their booking. The code for interacting with S3 remains the same, requiring only a change in the connection parameters to switch between LocalStack and AWS. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;create_booking.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateBookingUseCase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;dynamodb_client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DynamoDBClientDependency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;s3_client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;S3ClientDependency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="p"&gt;):&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dynamodb_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb_client&lt;/span&gt; 
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s3_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3_client&lt;/span&gt; 

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CreateBooking&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Booking&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;booking_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 

        &lt;span class="n"&gt;booking&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Booking&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
            &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 
            &lt;span class="n"&gt;booking_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;booking_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
        &lt;span class="p"&gt;)&lt;/span&gt; 

        &lt;span class="n"&gt;pdf_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;booking&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

        &lt;span class="n"&gt;s3_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;booking_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s3_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
            &lt;span class="n"&gt;pdf_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;booking_bucket_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;s3_key&lt;/span&gt; 
        &lt;span class="p"&gt;)&lt;/span&gt; 

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dynamodb_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
            &lt;span class="n"&gt;TableName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;booking_table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;booking_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;booking_id&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;customer_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;booking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;check_in&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;booking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_in&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;check_out&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;booking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_out&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;room_type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;booking&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;room_type&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pdf_url&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;S&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;booking_bucket_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;s3_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&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;return&lt;/span&gt; &lt;span class="n"&gt;booking&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;libs/aws.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;start_local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;START_LOCAL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

&lt;span class="n"&gt;LOCALSTACK_ENDPOINT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://localhost:4566&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; 
&lt;span class="n"&gt;LOCALSTACK_AWS_REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; 
&lt;span class="n"&gt;LOCALSTACK_ACCESS_KEY_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; 
&lt;span class="n"&gt;LOCALSTACK_SECRET_ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; 


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_s3_client&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_local&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LOCALSTACK_ENDPOINT&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOCALSTACK_ENDPOINT_URL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
            &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS_REGION&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOCALSTACK_AWS_REGION&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
            &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LOCALSTACK_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LOCALSTACK_SECRET_ACCESS_KEY&lt;/span&gt; 
        &lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_dynamodb_client&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_local&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LOCALSTACK_ENDPOINT&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOCALSTACK_ENDPOINT_URL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
            &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;AWS_REGION&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOCALSTACK_AWS_REGION&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
            &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LOCALSTACK_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LOCALSTACK_SECRET_ACCESS_KEY&lt;/span&gt; 
        &lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 


&lt;span class="n"&gt;S3ClientDependency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_s3_client&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
&lt;span class="n"&gt;DynamoDBClientDependency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Annotated&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_dynamodb_client&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Start the FastAPI local application with localstack
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;START_LOCAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 poetry run uvicorn app.main:app &lt;span class="nt"&gt;--reload&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  End-to-End Testing without Mocking AWS Services
&lt;/h2&gt;

&lt;p&gt;With LocalStack, developers can perform true end-to-end testing without the need to mock AWS services. This allows teams to validate the entire workflow of their applications in a real-world environment before deployment. By simulating services like DynamoDB and S3, developers can verify that their code interacts correctly with these components, ensuring that functionalities such as creating bookings and storing receipts work as intended. This approach provides invaluable feedback, exposing potential issues early in the development process. Since the tests run against services that behave like their AWS counterparts, it increases confidence that the application will perform reliably in production. Overall, LocalStack helps maintain a high level of code quality by allowing thorough testing without the complexities and costs associated with using real AWS resources. &lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying Operation Success with AWS CLI
&lt;/h2&gt;

&lt;p&gt;Using the AWS Command Line Interface (CLI), developers can easily verify the success of operations performed on AWS services like DynamoDB and S3. With LocalStack running, the AWS CLI can be configured to point to the local endpoints, allowing for straightforward management and verification of resources. &lt;/p&gt;

&lt;p&gt;For instance, to check the data within a DynamoDB table, you can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4566 &lt;span class="nt"&gt;--profile&lt;/span&gt; localstack dynamodb scan &lt;span class="nt"&gt;--table-name&lt;/span&gt; booking 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will return a list of all items stored in the "booking" table, allowing you to confirm that your application is correctly saving booking details. &lt;/p&gt;

&lt;p&gt;Similarly, to read the contents of an S3 bucket or download a file to your local machine, you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4566 &lt;span class="nt"&gt;--profile&lt;/span&gt; localstack s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://booking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or to download a specific file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:4566 &lt;span class="nt"&gt;--profile&lt;/span&gt; localstack &lt;span class="nb"&gt;cp &lt;/span&gt;s3://booking/&lt;span class="si"&gt;$(&lt;/span&gt;key&lt;span class="si"&gt;)&lt;/span&gt; ./downloads
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands facilitate the verification of operations and help ensure that the application is functioning as expected, both locally with LocalStack and when deployed to the cloud. Leveraging the AWS CLI enhances the development workflow by providing direct access to data, making it easier to troubleshoot and validate application behavior. &lt;/p&gt;

&lt;p&gt;As an alternative to configuring the AWS profile, developers can use awscli-local, a wrapper for the AWS CLI designed specifically for LocalStack. This tool simplifies the process by automatically setting the correct parameters and endpoints for local development. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using LocalStack in your cloud application development streamlines testing and validation without relying on real AWS resources. By focusing on external dependencies and utilizing tools like Boto3 and the AWS CLI, developers can create a seamless environment that mirrors production. This approach enhances productivity, increases confidence in application reliability, and leads to higher-quality software before deployment in the cloud. &lt;/p&gt;

&lt;p&gt;For a practical example of these concepts in action, you can explore the repository at this &lt;a href="https://github.com/claranet-it/devrel-localstack" rel="noopener noreferrer"&gt;GitHub link&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>development</category>
      <category>testing</category>
      <category>coding</category>
    </item>
    <item>
      <title>Infusing Conversational AI in Your Business with Amazon Lex</title>
      <dc:creator>Massimo Biagioli</dc:creator>
      <pubDate>Tue, 29 Apr 2025 06:20:27 +0000</pubDate>
      <link>https://dev.to/claranet/infusing-conversational-ai-in-your-business-with-amazon-lex-4mac</link>
      <guid>https://dev.to/claranet/infusing-conversational-ai-in-your-business-with-amazon-lex-4mac</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In an era where instant and interactive customer service is the norm, Amazon Lex emerges as a transformative solution, enabling businesses to build sophisticated, AI-powered chatbots and voice assistants.  &lt;/p&gt;

&lt;p&gt;This technology leverages the same deep learning functionalities that power Amazon Alexa, making it possible to design conversational interfaces that genuinely understand the user's intent.  &lt;/p&gt;

&lt;p&gt;Amazon Lex automates interactions, offering a seamless, 24/7 customer engagement model that scales as your business grows.  &lt;/p&gt;

&lt;p&gt;This not only enhances user experience but also significantly reduces operational costs. &lt;/p&gt;

&lt;h2&gt;
  
  
  Business Needs
&lt;/h2&gt;

&lt;p&gt;In today's fast-paced digital landscape, companies face a critical challenge: meeting customer demands for immediate support without straining their resources.  &lt;/p&gt;

&lt;p&gt;Long wait times and inadequate responses can lead to frustration and lost trust. There is a pressing need for solutions that enhance service efficiency while minimizing operational costs.  &lt;/p&gt;

&lt;p&gt;As customer expectations continue to rise, the inability to provide personalized interactions risks driving customers away.  &lt;/p&gt;

&lt;p&gt;Therefore, leveraging conversational AI like Amazon Lex becomes essential in effectively addressing these pain points. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Amazon Lex
&lt;/h2&gt;

&lt;p&gt;Amazon Lex is a powerful service that enables businesses to build conversational interfaces using voice and text, effectively addressing the challenges of providing timely and accurate customer support.  &lt;/p&gt;

&lt;p&gt;By automating interactions, it significantly reduces response times and improves user satisfaction. &lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Natural Language Understanding (NLU)&lt;/strong&gt;: Amazon Lex uses advanced machine learning to understand user intents and context, improving the accuracy of interactions. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Channel Support&lt;/strong&gt;: The service allows seamless integration with various platforms, including web applications, mobile apps, and messaging services, ensuring a consistent user experience. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Lex is designed to easily scale with your business needs, efficiently handling increasing interaction volumes as your customer base grows. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key Concepts in Amazon Lex
&lt;/h3&gt;

&lt;p&gt;To effectively utilize Amazon Lex, it is essential to understand its key concepts: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Utterance&lt;/strong&gt;: An utterance is what the user says or types to interact with the chatbot. It represents the user's input, which Lex will interpret to determine the desired action. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intent&lt;/strong&gt;: An intent is a mapping between what the user wants to accomplish and a specific action that the application should take. Each intent corresponds to a unique user goal, such as retrieving information or performing an action. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Slots&lt;/strong&gt;: Slots are variables that capture specific pieces of information from the user's utterance needed to fulfill an intent. They act as placeholders that get filled in with data extracted from the user's input, such as dates or locations. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider the following examples of user utterances that correspond to an intent for retrieving warehouse movements:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Get all movements for warehouse {warehouse} on {date}  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Give me all movements from warehouse {warehouse} on {date}  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In these examples, {warehouse} and {date} are slots that will be populated with the specific warehouse name and date provided by the user, allowing the system to retrieve the relevant information. &lt;/p&gt;

&lt;h2&gt;
  
  
  A First, Simple Scenario
&lt;/h2&gt;

&lt;p&gt;Imagine needing a chatbot integrated into an inventory management system. When a user interacts with the chatbot, it triggers Amazon Lex, which processes the user's request. Lex then invokes an AWS Lambda function that interprets the prompt and queries data stored in DynamoDB. After retrieving the necessary information, the Lambda function formats the response and sends it back to Lex. Finally, Lex delivers this information back to the user, ensuring a seamless and efficient interaction. &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%2F3bkay1rywb9y3bloy4me.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%2F3bkay1rywb9y3bloy4me.png" alt="Image description" width="609" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s inspect the lambda
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;lambda_handler.py&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;warehouse_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_movements_by_warehouse_and_date&lt;/span&gt; 


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="n"&gt;slots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;currentIntent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;slots&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="n"&gt;warehouse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;warehouse&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
    &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 

    &lt;span class="n"&gt;movements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_movements_by_warehouse_and_date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;warehouse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;movements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;movement_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;movements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="n"&gt;response_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sure, here is the list of movements: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;movement_list&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;response_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;There are no recorded movements for the given warehouse and date.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; 

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dialogAction&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Close&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fulfillmentState&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Fulfilled&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;contentType&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PlainText&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response_message&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;&lt;strong&gt;warehouse_service.py&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt; 
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;boto3.dynamodb.conditions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt; 
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;botocore.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt; 

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;warehouse_movement_item&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WarehouseMovementItem&lt;/span&gt; 

&lt;span class="n"&gt;TABLE_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;devrel-chatbot-dev-warehouse&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; 

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_movements_by_warehouse_and_date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;warehouse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;operation_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WarehouseMovementItem&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; 
    &lt;span class="n"&gt;dynamodb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dynamodb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; 
            &lt;span class="n"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pk&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;warehouse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; 
                                   &lt;span class="nc"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sk&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation_date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;)&lt;/span&gt; 

        &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Items&lt;/span&gt;&lt;span class="sh"&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;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WarehouseMovementItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to retrieve items: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the DynamoDB table’s data: &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%2Flrps4p190of7vqtc73n1.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%2Flrps4p190of7vqtc73n1.png" alt="Image description" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup the ChatBot with IaC with Terraform
&lt;/h3&gt;

&lt;p&gt;Terraform is an open-source tool that enables Infrastructure as Code (IaC), allowing you to define and provision cloud resources through configuration files.  &lt;/p&gt;

&lt;p&gt;The entire infrastructure, including AWS Lambda and DynamoDB, has already been provisioned with Terraform.  &lt;/p&gt;

&lt;p&gt;Below are code snippets to set up a chatbot using Amazon Lex with Terraform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lex_bot"&lt;/span&gt; &lt;span class="s2"&gt;"warehouse_bot"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"WarehouseBot"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Chatbot for warehouse movements queries"&lt;/span&gt;
  &lt;span class="nx"&gt;process_behavior&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"BUILD"&lt;/span&gt;
  &lt;span class="nx"&gt;idle_session_ttl_in_seconds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="c1"&gt;# 5 minutes&lt;/span&gt;
  &lt;span class="nx"&gt;enable_model_improvements&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;locale&lt;/span&gt;                      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"en-US"&lt;/span&gt;
  &lt;span class="nx"&gt;child_directed&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="nx"&gt;abort_statement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;content&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Sorry, I couldn't process your request. Please try again."&lt;/span&gt;
      &lt;span class="nx"&gt;content_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PlainText"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;clarification_prompt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;max_attempts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;content&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"I didn't understand you. Could you please rephrase your request?"&lt;/span&gt;
      &lt;span class="nx"&gt;content_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PlainText"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;intent_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lex_intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;warehouse_movements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
    &lt;span class="nx"&gt;intent_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lex_intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;warehouse_movements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lex_intent"&lt;/span&gt; &lt;span class="s2"&gt;"warehouse_movements"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"GetWarehouseMovements"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Intent to get warehouse movements for a specific date"&lt;/span&gt;

  &lt;span class="nx"&gt;sample_utterances&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s2"&gt;"Get all movements for warehouse {warehouse} on {date}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"Show me movements for warehouse {warehouse} on {date}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"List all warehouse {warehouse} movements for {date}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"Give me all movements from warehouse {warehouse} on {date}"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;fulfillment_activity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CodeHook"&lt;/span&gt;
    &lt;span class="nx"&gt;code_hook&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;message_version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1.0"&lt;/span&gt;
      &lt;span class="nx"&gt;uri&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chatbot_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;slot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"warehouse"&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The warehouse identifier"&lt;/span&gt;
    &lt;span class="nx"&gt;slot_constraint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Required"&lt;/span&gt;
    &lt;span class="nx"&gt;slot_type&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AMAZON.AlphaNumeric"&lt;/span&gt;
    &lt;span class="nx"&gt;value_elicitation_prompt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;max_attempts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;content&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Which warehouse are you interested in?"&lt;/span&gt;
        &lt;span class="nx"&gt;content_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PlainText"&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="nx"&gt;slot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"date"&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"The date of movements"&lt;/span&gt;
    &lt;span class="nx"&gt;slot_constraint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Required"&lt;/span&gt;
    &lt;span class="nx"&gt;slot_type&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AMAZON.AlphaNumeric"&lt;/span&gt;
    &lt;span class="nx"&gt;value_elicitation_prompt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;max_attempts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;content&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"For which date would you like to see movements?"&lt;/span&gt;
        &lt;span class="nx"&gt;content_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PlainText"&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;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lambda_permission"&lt;/span&gt; &lt;span class="s2"&gt;"lex_invoke_permission_generic"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;statement_id&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AllowExecutionFromLexGeneric"&lt;/span&gt;
  &lt;span class="nx"&gt;action&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lambda:InvokeFunction"&lt;/span&gt;
  &lt;span class="nx"&gt;function_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chatbot_lambda_function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;function_name&lt;/span&gt;
  &lt;span class="nx"&gt;principal&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"lex.amazonaws.com"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Linking Lambda and the Chatbot
&lt;/h3&gt;

&lt;p&gt;The connection between the AWS Lambda function and the chatbot in Amazon Lex is established through the “fulfillment_activity”  section, utilizing a code hook. This code hook specifies that the Lambda function will be invoked to handle the logic required to fulfill the user's intent.  &lt;/p&gt;

&lt;p&gt;When a user interacts with the chatbot and their request is matched to a specific intent, the corresponding Lambda function is triggered, allowing it to process the necessary data and return a response back to Amazon Lex for the user.  &lt;/p&gt;

&lt;p&gt;This integration ensures dynamic and efficient handling of user interactions. &lt;/p&gt;

&lt;h3&gt;
  
  
  Let's See the Chatbot in Action
&lt;/h3&gt;

&lt;p&gt;Using the AWS Management Console, it is possible to test the chatbot in real-time, allowing users to interact with it directly and observe its responses to different inputs. &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%2F8xohb39m4p35fgcld48h.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%2F8xohb39m4p35fgcld48h.png" alt="Image description" width="616" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A More Complex Scenario - Leveraging Generative AI with Bedrock
&lt;/h2&gt;

&lt;p&gt;Now that the foundational components for building a chatbot have been established, it's possible to explore more advanced functionalities by integrating the Lambda function not only with DynamoDB but also with powerful services like Amazon Bedrock. Amazon Bedrock is a fully managed service that makes it easier for developers to build and scale generative AI applications using foundation models. &lt;/p&gt;

&lt;p&gt;By leveraging Bedrock, businesses can enhance user interactions by utilizing advanced natural language processing capabilities, enabling more nuanced conversations with customers. This integration can significantly improve the chatbot's ability to understand complex queries and deliver more insightful responses. &lt;/p&gt;

&lt;p&gt;From a business perspective, this translates to a superior customer experience, as users can engage in more meaningful dialogues and obtain relevant information quickly. Moreover, by providing a richer interaction model, companies can drive higher customer satisfaction and loyalty, ultimately leading to increased operational efficiency and effectiveness in meeting user needs. &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%2Fjnqqzowofsyngb8ao3mu.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%2Fjnqqzowofsyngb8ao3mu.png" alt="Image description" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In an increasingly competitive landscape, businesses face the critical challenge of meeting customer expectations for fast and effective support. By addressing these needs through innovative solutions, companies can enhance customer satisfaction and operational efficiency. Generative AI serves as a powerful tool in this regard, enabling more sophisticated interactions that go beyond basic queries. &lt;/p&gt;

&lt;p&gt;Integrating a chatbot with advanced services, such as Amazon Bedrock, empowers businesses to create dynamic and meaningful conversations with users. These interactions not only provide immediate answers but also foster a deeper understanding of customer needs. &lt;/p&gt;

&lt;p&gt;AWS stands out as a leader in offering a comprehensive suite of interconnected services that can be easily assembled to meet varying business demands. By leveraging AWS's powerful tools, organizations can build robust solutions that align with both user expectations and business objectives, ultimately driving growth and success in their respective markets. &lt;/p&gt;

&lt;p&gt;For a practical example of these concepts in action, you can explore the repository at this &lt;a href="https://github.com/claranet-it/devrel-conversational-ai" rel="noopener noreferrer"&gt;GitHub link&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>lex</category>
      <category>devops</category>
    </item>
    <item>
      <title>Prompt engineering and other fantastic creatures</title>
      <dc:creator>Davide Donadio</dc:creator>
      <pubDate>Tue, 01 Apr 2025 13:00:55 +0000</pubDate>
      <link>https://dev.to/claranet/prompt-engineering-and-other-fantastic-creatures-i8p</link>
      <guid>https://dev.to/claranet/prompt-engineering-and-other-fantastic-creatures-i8p</guid>
      <description>&lt;p&gt;&lt;strong&gt;Harnessing the Power of Prompt Engineering in AI Development&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Prompt engineering serves as a crucial interface between human operators and Artificial Intelligence (AI), particularly in optimizing the utility of Large Language Models (LLMs). Here, we explore how various prompt engineering techniques enhance interactions with AI to achieve precise and practical outcomes, fundamentally advancing AI functionalities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Foundation Models and LLMs
&lt;/h3&gt;

&lt;p&gt;At the foundation of prompt engineering are the robust LLMs, trained on vast datasets to comprehend and replicate human-like text interaction. These models are adept at tasks that require little to no additional tuning, leveraging their capabilities through effectively designed prompts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Applications
&lt;/h3&gt;

&lt;p&gt;In practical terms, LLMs have been instrumental across various fields, from easing content creation processes in digital marketing to enhancing decision-making in financial analysis. The flexibility of LLMs to adapt to different tasks makes them invaluable across sectors.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Essence of Prompt Engineering: Dissecting the Components of a Prompt&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Prompt engineering is crucial for optimizing interactions with AI models, ensuring they produce accurate and relevant responses. Each prompt consists of several key elements:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Instruction
&lt;/h4&gt;

&lt;p&gt;This is the directive part of the prompt, clearly telling the AI the task to perform, such as “summarize the text.”&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Data Input
&lt;/h4&gt;

&lt;p&gt;It represents the content on which the AI acts, like a specific text or question, directly influencing the AI’s response.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Output Format
&lt;/h4&gt;

&lt;p&gt;This specifies how the response should be structured, ensuring it meets certain criteria like a full sentence or a list.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Context
&lt;/h4&gt;

&lt;p&gt;Providing relevant background or additional information can significantly enhance the effectiveness and relevance of the AI’s output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crafting the Perfect Prompt&lt;/strong&gt;: For example, to analyze customer feedback sentiment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Instruction&lt;/strong&gt;: Report the sentiment of the feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Input&lt;/strong&gt;: The text of the feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output Format&lt;/strong&gt;: Categorize as positive, negative, or neutral.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context&lt;/strong&gt;: Information about the related product/service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By meticulously combining these components, prompt engineering transforms the capabilities of AI models to deliver more precise and practical outcomes.&lt;/p&gt;

&lt;p&gt;Prompt engineering refines how these models receive and process inputs, thereby shaping their outputs. It ensures that the interactions are aligned with the specific needs of the task, which can dramatically affect the usability and accuracy of the AI's responses. Here's a deeper look at some of the pivotal prompt engineering techniques:&lt;/p&gt;

&lt;h3&gt;
  
  
  Zero-Shot Prompting
&lt;/h3&gt;

&lt;p&gt;Zero-shot prompting is a technique where the model is directed to execute a task without the use of examples or demonstrations within the prompt itself. This approach relies purely on the model’s pre-trained understanding to carry out specific instructions.&lt;/p&gt;

&lt;p&gt;In our exploration, we employed several zero-shot prompts, such as the following text classification example:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Classify the text into neutral, negative, or positive.
Text: I think the vacation is okay. Sentiment:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Output:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Neutral
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enhancements in zero-shot learning have been linked to instruction tuning, as demonstrated by research from Wei et al. (2022), which can be found &lt;a href="https://arxiv.org/pdf/2109.01652.pdf" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Instruction tuning involves refining models through training on datasets that are explicitly described via instructions. Additionally, the method of Reinforcement Learning from Human Feedback (RLHF) explored &lt;a href="https://arxiv.org/abs/1706.03741" rel="noopener noreferrer"&gt;here&lt;/a&gt; has been instrumental in scaling instruction tuning by aligning the model more closely with human preferences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Few-Shot Prompting
&lt;/h3&gt;

&lt;p&gt;Few-shot prompting is a technique that enhances model performance by providing specific examples within the prompt. These examples condition the model, helping it learn the context and improve its responses for subsequent queries.&lt;/p&gt;

&lt;p&gt;Research by Touvron et al. (2023) indicates that the benefits of few-shot prompting emerged as models were scaled up significantly (Kaplan et al., 2020).&lt;/p&gt;

&lt;p&gt;Here's an application of few-shot prompting demonstrated by Brown et al. (2020):&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A "whatpu" is a small, furry animal native to Tanzania.
Use "whatpu" in a sentence.
Example: We were traveling in Africa and we saw these very cute whatpus.

To define a "farduddle" means to jump up and down really fast.
Use "farduddle" in a sentence.

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Output:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When we won the game, we all started to farduddle in celebration.

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

&lt;/div&gt;



&lt;p&gt;This example shows that the model can effectively apply a new word in context with just a single example provided (1-shot). For more complex tasks, increasing the number of examples (3-shot, 5-shot, etc.) might be necessary.&lt;/p&gt;

&lt;p&gt;According to Min et al. (2022), when using few-shot prompting, the choice of labels and the distribution of input text provided as examples are crucial—even if the labels aren't individually accurate. The format of the examples also significantly influences performance; surprisingly, using random labels is more effective than providing no labels. Optimal results are obtained when labels are randomly chosen from an accurate distribution rather than uniformly, which underscores the importance of how demonstrations are structured.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chain-of-Thought Prompting
&lt;/h3&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%2Fpxn7zxc7wkn5ms20e8m3.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%2Fpxn7zxc7wkn5ms20e8m3.png" alt="CoT prompting" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Introduced by Wei et al. (2022) in their research, chain-of-thought (CoT) prompting facilitates complex reasoning in AI models by guiding them through intermediate steps before arriving at a final response. This method can be further enhanced by combining it with few-shot prompting for tasks that demand intricate reasoning.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The odd numbers in this group add up to an even number: 4, 8, 9, 15, 12, 2, 1.
Adding all the odd numbers (9, 15, 1) totals 25.
The answer is False.

The odd numbers in this group add up to an even number: 17,  10, 19, 4, 8, 12, 24. 
Adding all the odd numbers (17, 19) totals 36. 
The answer is True.

The odd numbers in this group add up to an even number: 16,  11, 14, 4, 8, 13, 24. 
Adding all the odd numbers (11, 13) totals 24. 
The answer is True.

The odd numbers in this group add up to an even number: 17,  9, 10, 12, 13, 4, 2. 
Adding all the odd numbers (17, 9, 13) totals 39. 
The answer is False.

The odd numbers in this group add up to an even number: 15, 32, 5, 13, 82, 7, 1.

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Output:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Adding all the odd numbers (15, 5, 13, 7, 1) totals 41. 
The answer is False.

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

&lt;/div&gt;



&lt;p&gt;This example clearly demonstrates the precision achieved with CoT prompting. Remarkably, we observed that even a single example can sufficiently guide the model to solve such arithmetic tasks correctly:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The odd numbers in this group add up to an even number: 4, 8, 9, 15, 12, 2, 1. Adding all the odd numbers (9, 15, 1) totals 25. The answer is False.
The odd numbers in this group add up to an even number: 15, 32, 5, 13, 82, 7, 1.

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Output:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Adding all the odd numbers (15, 5, 13, 7, 1) totals 41. The answer is False.

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step-back Prompting
&lt;/h3&gt;

&lt;p&gt;Step-Back Prompting is a method aimed at enhancing the problem-solving capabilities of LLMs by prompting them to abstract general principles before diving into detailed reasoning. This technique encourages models to focus on high-level concepts, thereby minimizing errors in the processing steps and improving the accuracy of their conclusions. &lt;a href="https://arxiv.org/abs/2310.06117" rel="noopener noreferrer"&gt;Zheng et al. (2024)&lt;/a&gt; outline this approach in their work, highlighting its efficacy in reasoning-heavy tasks across fields like STEM, knowledge-based QA, and multi-hop reasoning. The method has shown notable improvements in models like PaLM-2L, GPT-4, and Llama2-70B, outperforming traditional techniques such as Chain-of-Thought Prompting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Step-Back Prompting Operates:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Abstraction:&lt;/strong&gt; Initially, the model is prompted to consider the overarching principle or concept relevant to the query.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning:&lt;/strong&gt; Leveraging this high-level abstraction, the model then addresses the specifics of the question.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Prompt:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Question: "What happens to the pressure of an ideal gas if the temperature is increased by a factor of 2 and the volume is increased by a factor of 8?"
Abstraction: The model determines the relevant principle: "Ideal Gas Law."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Output:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Answer: Applying this law, it calculates that the pressure decreases by a factor of 4.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ReAct Prompting
&lt;/h3&gt;

&lt;p&gt;In 2022, Yao et al. introduced the ReAct framework, which enhances the functionality of Large Language Models (LLMs) by enabling them to generate reasoning traces and perform task-specific actions in a synchronized manner.&lt;/p&gt;

&lt;p&gt;The capability to produce reasoning traces allows the model to develop, monitor, and revise action plans effectively, and even manage exceptions as they arise. The action component of ReAct facilitates the integration with external sources, such as knowledge bases or other environments, enabling the model to gather supplementary information.&lt;/p&gt;

&lt;p&gt;ReAct significantly augments the capacity of LLMs to interact with external tools, securing more accurate and fact-based responses. The framework has demonstrated superior performance over various state-of-the-art methods in tasks involving language processing and decision-making. Moreover, the integration of ReAct with the chain-of-thought (CoT) prompting enriches the model's responses with both internal knowledge and externally acquired information, enhancing the interpretability and trustworthiness of LLMs.&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%2Ffh9nkzml05dlhepihu3h.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%2Ffh9nkzml05dlhepihu3h.png" alt="ReAct prompting" width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ReAct is predicated on the interplay between 'acting' and 'reasoning', a combination pivotal for humans learning new tasks or making reasoned decisions. While CoT prompting has proven effective in enabling LLMs to trace logical reasoning in solving problems, it traditionally lacks the capability to interact with the external environment, which can lead to inaccuracies such as fact fabrication.&lt;/p&gt;

&lt;p&gt;As a solution, ReAct amalgamates the concepts of reasoning and acting. It instructs LLMs to articulate verbal reasoning passages and enact specific actions relevant to the task at hand. This dual capability not only allows for dynamic and adaptable reasoning but also the integration of new information from external sources into the model’s framework, as depicted in the following example illustration of ReAct for a question-answering task.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Impact and Future of Prompt Engineering
&lt;/h3&gt;

&lt;p&gt;The advancement in prompt engineering techniques is not just enhancing the functionality of AI models but also expanding their potential applications. By improving how we structure inputs and interpret outputs, AI becomes a more powerful tool, capable of undertaking complex tasks with greater autonomy and accuracy.&lt;/p&gt;

&lt;p&gt;As we continue to push the boundaries of what AI can achieve through sophisticated prompt engineering, the prospects for future technology—where humans and machines collaborate seamlessly—are immensely promising.&lt;/p&gt;

</description>
      <category>promptengineering</category>
      <category>ai</category>
    </item>
    <item>
      <title>Frontend Rendering: How to Not Mess with SPAs, SSR &amp; Friends</title>
      <dc:creator>Leonardo Montini</dc:creator>
      <pubDate>Tue, 25 Mar 2025 08:02:04 +0000</pubDate>
      <link>https://dev.to/claranet/frontend-rendering-how-to-not-mess-with-spas-ssr-friends-3515</link>
      <guid>https://dev.to/claranet/frontend-rendering-how-to-not-mess-with-spas-ssr-friends-3515</guid>
      <description>&lt;p&gt;The rendering strategy of a web application also defines its architecture and once you decide, it might not be trivial to transition away. &lt;/p&gt;

&lt;p&gt;The question is: where is your content rendered? On the server or on the client? &lt;/p&gt;

&lt;p&gt;Don’t be fooled though, the path to find the answer is way less technical than you might think! &lt;/p&gt;

&lt;p&gt;Let's try to understand what’s hidden behind the buzzwords we see so often, SPA vs MPA and then CSR, SSR, SSG and everything else in between. &lt;/p&gt;

&lt;p&gt;That’s funny how we like acronyms to make it easy to communicate but we use so many to the point sometimes it’s more confusing than ever. &lt;/p&gt;

&lt;h2&gt;
  
  
  The old problems
&lt;/h2&gt;

&lt;p&gt;How did we end up with so many different techniques of just showing a web page to our users? We can try to understand that by looking at the past. &lt;/p&gt;

&lt;p&gt;Let’s do a quick recap to understand the reasons behind each step. &lt;/p&gt;

&lt;h3&gt;
  
  
  The early, static, web
&lt;/h3&gt;

&lt;p&gt;Ah the good old days where the web was just a collection of many static html pages, written once and published, then served as is. &lt;/p&gt;

&lt;p&gt;Navigation is simply requesting a new page to the server and displaying it on the browser. &lt;/p&gt;

&lt;p&gt;At first that was working fine, but updating the content meant having the developers to update the files and do a full deploy. Ok that was probably just swapping the old file with the new one but still updating something across the entire website meant doing that manually on each file, every time. &lt;/p&gt;

&lt;h3&gt;
  
  
  Rendering on the server
&lt;/h3&gt;

&lt;p&gt;Static files were kind of a limitation, that’s why we made our web server smarter and instead of uploading pages with the full content we began creating templates. Those templates were then filled on the server by accessing the database and dynamically rendering HTML code. The final page with fresh data was then sent back to the browser. &lt;/p&gt;

&lt;p&gt;That was such a great idea, but this moved a lot of extra pressure on servers that now had to do much more than just serving static files, we needed a solution. &lt;/p&gt;

&lt;h3&gt;
  
  
  Render on the Client
&lt;/h3&gt;

&lt;p&gt;With the rise of AJAX we moved some load to the client that could at that time update just a portion of the page by requesting the raw data to the server and demanding the rendering duty to the browser. &lt;/p&gt;

&lt;p&gt;We achieved interactivity without the need of reloading the entire page and distributed to the users some of the load previously on the server for everyone. Faster for the user and cheaper for the server. &lt;/p&gt;

&lt;p&gt;If you push his approach of rendering everything on the client to its limits you no longer need to navigate between pages, you just need a single index.html and then navigation becomes simply replacing the content of the entire page with something else. &lt;/p&gt;

&lt;p&gt;Such a great idea! However, search engine crawlers didn’t use to run javascript which meant pages rendered on the client were having a hard time being indexed, destroying their SEO. User interaction also wasn’t that great with slow connections or low-end devices, not powerful enough to take that duty we just got off the server, for example by showing empty pages as the content was loading. &lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s render server side again
&lt;/h3&gt;

&lt;p&gt;Modern frameworks like Next.js or Nuxt can do an initial render on the server so that SEO is happy and send a fully rendered page on the client so that the user immediately gets a fully formed page with data and all HTML components. &lt;/p&gt;

&lt;p&gt;The javascript bundle is loaded separately (hydration) so that the page might be unresponsive at first but if done properly that shouldn’t even be noticeable by the user, as in fact the UI is entirely loaded. &lt;/p&gt;

&lt;p&gt;Such a great idea! However going back to servers also brought back the old problems like excessive load and more complexity in deployments. &lt;/p&gt;

&lt;p&gt;Caching might be a solution in some cases, in particular for those pages that might not update so often and that’s why we invented a completely new and unprecedented approach: letting the server reply with a static and fully rendered page! &lt;/p&gt;

&lt;h3&gt;
  
  
  What about rendering just once?
&lt;/h3&gt;

&lt;p&gt;If a website doesn’t update its content so often like a blog or a marketing page, it might actually make sense to travel back in time where pages were just served as-is, and that’s what we call today SSG. &lt;/p&gt;

&lt;p&gt;To be fair it’s slightly more advanced than 30 years ago as we now have introduced a build process that can smartly optimize and dynamically generate pages all at once, but the overall idea is exactly the same: to serve files as is. This also includes JavaScript code for interactivity if needed. &lt;/p&gt;

&lt;p&gt;That’s a smart idea right? But we’re intentionally back at the point where in order to update some data you have to rebuild (and redeploy) your entire application. &lt;/p&gt;

&lt;h2&gt;
  
  
  Running in circles
&lt;/h2&gt;

&lt;p&gt;History often repeats itself, and software development is no exception. However, one advantage we have is the ability to learn from past experiences and use that knowledge to make better decisions today. An example is the rise of meta metaframeworks, wrappers to the most famous client side frameworks enabling them with server side capabilities. &lt;/p&gt;

&lt;p&gt;At the core, though, we’re still dealing with the same fundamental structure: computation that runs on the user’s device versus computation that runs somewhere else (a server, cloud function or someone else’s computer in general). All the modern solutions we have today are different ways of managing this split. &lt;/p&gt;

&lt;p&gt;Even if we see a new JavaScript framework rise every other day, it’s all about combining and enhancing what we already have (and always had). &lt;/p&gt;

&lt;h3&gt;
  
  
  Informed Decisions Require Informed Developers
&lt;/h3&gt;

&lt;p&gt;To make the right architectural choice, we must first understand the needs of our business and the requirements of our application. By knowing what we aim to achieve, we can smartly pick an approach with the right tradeoffs, the one which brings the benefits we need at the cost of some downsides we can ignore or are less impactful in our domain. &lt;/p&gt;

&lt;p&gt;There’s no silver bullet or one size fits all, unfortunately. &lt;/p&gt;

&lt;p&gt;It’s also tempting to follow what’s hyped and most talked around, if it’s the latest piece of tech it has to be the best, right? Well... that’s wrong. &lt;/p&gt;

&lt;p&gt;As technical people we like to talk about tech, but we should never forget that the architecture of our application should be driven by the business needs. &lt;/p&gt;

&lt;p&gt;It’s time to get more into detail for some approaches, what value they provide to the end user at what cost. &lt;/p&gt;

&lt;h2&gt;
  
  
  Single-Page Applications vs Multi Page Applications
&lt;/h2&gt;

&lt;p&gt;Let’s briefly talk about this difference as it’s often confusing. SPAs are usually associated with CSR while MPAs are going together with SSR/SSG. While this is most often correct, it’s not actually a rule and some approaches might be mixed. &lt;/p&gt;

&lt;p&gt;In general, the biggest strength of SPAs is that navigation is basically a lie, it’s not really navigating to another page (as MPAs were doing since day 1) but it’s replacing the entire content with the new one, providing a really fast transition that brings a smooth user experience. This is usually a requirement for those kinds of applications that are highly interactive such as SaaS products, dashboards or social media apps. Faster navigation and interactions make them look much better in a customer’s eyes. &lt;/p&gt;

&lt;p&gt;Multi Page Applications still have their own use case that is taking care of content-heavy sites like an e-commerce, where it’s actually faster to delegate a big part of the work to the server and deliver to the client (and to search engine crawlers) a fully rendered page. &lt;/p&gt;

&lt;h2&gt;
  
  
  Where is your code rendered?
&lt;/h2&gt;

&lt;p&gt;Regardless of if your application is all in one page or split into multiple pages, the other huge architectural decision you have to take is where is your code rendered. Client or Server? And... how often? &lt;/p&gt;

&lt;h3&gt;
  
  
  Client Side Rendering (CSR)
&lt;/h3&gt;

&lt;p&gt;To get the most of CSR, this approach is usually combined with SPAs where the entire content of the page is replaced, without a real navigation. &lt;/p&gt;

&lt;p&gt;The key aspect of CSR is that the initial page sent from the server is not the final result, it is usually a minimal set of HTML tags paired with some JavaScript code that is in charge of creating all the rest of the page directly in the browser. &lt;/p&gt;

&lt;p&gt;After the initial page load, all other interactions with the server are only to request raw data, which will be then used by JavaScript to destroy and replace the needed HTML tags to render the updates. &lt;/p&gt;

&lt;p&gt;However, there are also some challenges. The initial load time can be slow because the entire application logic, including JavaScript bundles, must be downloaded before rendering the content. This can be mitigated through a smart way of chunking your bundle, which means splitting the code of your application into smaller parts and only send to the browser the ones you need depending on what the user is doing. &lt;/p&gt;

&lt;p&gt;The other downside is that this approach isn’t really SEO friendly. &lt;/p&gt;

&lt;p&gt;Nowadays search engine crawlers can run JavaScript code, but that might not be enough. The first page they see will likely be blank and this might have a negative impact. Your your page also must be optimized enough to render the content even with the very limited resources a crawler might have. &lt;/p&gt;

&lt;p&gt;You can still make it work with SEO, it’s just not as simple as with SSR. &lt;/p&gt;

&lt;h3&gt;
  
  
  Server-Side Rendering (SSR)
&lt;/h3&gt;

&lt;p&gt;In contrast to CSR, Server-Side Rendering (SSR) generates all (or most of) the HTML content on the server for each user request before sending it to the browser. This means that the page is already rendered when it reaches the user, leading to faster initial load times and better SEO performance. Frameworks like Next.js or TanStack Start for React and Nuxt for Vue provide built-in support for SSR, making it easier for developers to implement. &lt;/p&gt;

&lt;p&gt;Navigation usually (but not necessarily) happens through a real browser navigation where each page is an existing endpoint on the server delivering the page content. &lt;/p&gt;

&lt;p&gt;SSR is particularly beneficial for content-heavy websites, e-commerce platforms, and applications that need to rank well on search engines. Since the content is delivered pre-rendered, search engine crawlers can index it more efficiently. Additionally, SSR improves the performance of applications on low-powered devices because the rendering is done server-side rather than relying on the client. &lt;/p&gt;

&lt;p&gt;Despite these advantages, SSR has its downsides. Because the server has to generate a new page for every request, it can increase server load and reduce scalability compared to purely static solutions we’ll see in the next chapter. Additionally, while SSR ensures fast initial page loads, subsequent interactions may not feel as smooth as those in an SPA, since every new interaction may require a server request. &lt;/p&gt;

&lt;h3&gt;
  
  
  Static Site Generation (SSG)
&lt;/h3&gt;

&lt;p&gt;Static Site Generation takes a different MPA approach by pre-building HTML files at build time rather than generating them dynamically for each request. This means that once the site is deployed, pages can be served instantly from a Content Delivery Network (CDN) without requiring further computation. Frameworks like Next.js, Gatsby, and Astro offer powerful tools for static site generation. &lt;/p&gt;

&lt;p&gt;Navigation feels much like the good old days, each path means the server will provide the fully rendered page, as is. &lt;/p&gt;

&lt;p&gt;For this reason, SSG is the optimal choice for websites where content does not change frequently, such as personal blogs, documentation sites, and marketing pages. Because the pages are already generated, they load almost instantly, providing an exceptional user experience and reducing server costs. Additionally, security risks are minimized since there is no need for active server-side processing. &lt;/p&gt;

&lt;p&gt;However, the static nature of SSG can be a limitation for sites requiring frequent updates. Any change to the content requires rebuilding the entire site, which can be time-consuming for large-scale applications. &lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental Static Regeneration
&lt;/h3&gt;

&lt;p&gt;Incremental Static Regeneration is a hybrid approach between SSR and SSG, trying to take the best of both worlds by fixing SSG’s biggest flaw, updates. &lt;/p&gt;

&lt;p&gt;ISR is performed by assigning to the pages some rules defining when they expire and need to be regenerated server side. &lt;/p&gt;

&lt;p&gt;From a client perspective it will always receive fully rendered pages, but the server can decide when it’s time to update the page and start serving the new version, without the need of manual interaction or redeploying the entire website. &lt;/p&gt;

&lt;p&gt;But what about the interactivity part of the page? Ah, there’s room for another entire article. &lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Architecture
&lt;/h2&gt;

&lt;p&gt;With all of that said, what we've seen is that web application architecture isn't a matter of right or wrong or following the trends, but of trade-offs... as everything else in the world. &lt;/p&gt;

&lt;p&gt;In a nutshell: SPAs prioritize a fluid user experience, while MPAs focus on content delivery. SSR aims for SEO benefits, SSG emphasizes speed, and ISR attempts to bridge the gap.  &lt;/p&gt;

&lt;p&gt;Ultimately, the best architecture is the one that effectively meets your business and user needs and sets you up for long-term maintainability and success. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>The best software architecture with the smaller effort</title>
      <dc:creator>Luca Nicolini</dc:creator>
      <pubDate>Wed, 05 Mar 2025 16:26:08 +0000</pubDate>
      <link>https://dev.to/claranet/the-best-software-architecture-with-the-smaller-effort-3njf</link>
      <guid>https://dev.to/claranet/the-best-software-architecture-with-the-smaller-effort-3njf</guid>
      <description>&lt;p&gt;For many years, code was written to create applications that got bigger and bigger, which we now call monolithic. Then we understood that this application was a big problem for businesses. Here are the main problems we have found with monolithic applications.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced development speed&lt;/strong&gt;: a large monolithic application makes development more complex and slower.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: scaling of individual components is not possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reliability&lt;/strong&gt;: failures in one module can affect the availability of the entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Non-Agile development&lt;/strong&gt;: Often more teams found a conflict in development code because they were working on the same code repository for different projects.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of flexibility&lt;/strong&gt;: a monolith is constrained by the technologies already used in the monolith itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;: a minor change to a monolithic application requires a re-deployment of the entire monolith.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fupn27axd2hfbqn4wcwhl.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%2Fupn27axd2hfbqn4wcwhl.png" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In recent years, many companies have migrated their monoliths to microservices architectures. Theoretically, I can assure you that it's the best choice, but in practice, there are different control indicators. Let's focus on the advantages of microservices over monoliths.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved scalability&lt;/strong&gt;: because each service is a separate component, it is possible to scale a single function or service without having to scale the entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Right tool for the right function&lt;/strong&gt;: with microservices, it is possible to achieve greater independence from suppliers by choosing the right tool for each function. Each service can be written in its own programming language, can use its own structure and utilities, and can communicate with the other services in the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Increased resilience&lt;/strong&gt;: with microservices, the entire application is decentralised and decoupled into services that act as separate entities. Unlike monolithic architecture, where a bug in the code affects more than one service or function, the impact of a bug in this architecture is minimal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faster deployment times&lt;/strong&gt;: in monolithic architectures, changes require redeploying the entire application. A microservices architecture enables faster releases because each service is developed and deployed independently, reducing the risk and time associated with coordinating changes across an entire application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Greater cost efficiency&lt;/strong&gt;: activities are focused on specific services, reducing the overall cost of developing and maintaining the system. Teams work on specific functionalities, ensuring that resources are used efficiently without redundancy or excess.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's talk about the drawbacks. When using microservice architecture there are two main disadvantages, in this article we'll focus on these ones and try to find a solution.&lt;/p&gt;

&lt;p&gt;The first contraindication is the cost of the infrastructure, but we won't talk about this because it was discussed in a previous article that you can find &lt;a href="https://dev.to/claranet/how-to-reduce-the-cost-of-microservices-architecture-ef4"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second contradiction we're going to talk about in this article is the implementation effort. Building a microservices architecture is very expensive, both in terms of development and in terms of maintenance and monitoring. It's important not to underestimate the difficulty of the design, a bad design will become the most important problem.&lt;/p&gt;

&lt;p&gt;There are companies that start a project with microservices and then come back because they understand that they are not ready for this architectural solution. Instead, there are companies that start migrating their monoliths to microservices and then stop because it's too expensive or too complicated.&lt;/p&gt;

&lt;p&gt;The solution I want to recommend to you today is semi-monolithic architecture. I am talking about a hybrid architecture that uses monolithic and microservices in total harmony.&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%2Fy1m3idetye1qcuvskgh1.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%2Fy1m3idetye1qcuvskgh1.png" alt="Image description" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows a hybrid microservices and monolithic architecture.&lt;/p&gt;

&lt;p&gt;I think that when you start a project you need to build a monolithic application. By monolithic I mean a large application that handles a significant part of the application domain. There may be more than one monolith in an organisation. The first thing you need to think about is dividing the application domain into a few parts and creating a monolithic application for each of them. You can think that a monolith needs to be only one, at actually we talk about monolith every time we have an application as managing a large part of the domain. So in a company there can be more monolithic application.&lt;/p&gt;

&lt;p&gt;If you need a common part for multiple monoliths, you can create a microservice instead of a library, giving you a piece of code that can be written in a different language, updated and deployed independently of other applications.&lt;/p&gt;

&lt;p&gt;Sometimes we need to create a microservice for a critical part that we can't scale horizontally. There are cases where we'll create a new microservice just because there's more functionality that's better implemented in a particular language. &lt;/p&gt;

&lt;p&gt;In this type of architecture, it's very important that services communicate with them in asynchronous mode, using message queues such as SQS in AWS services. For communication from monoliths to microservices we can use http protocol for example.&lt;/p&gt;

&lt;p&gt;Another important concept is that there will be no database sharing by applications. Each microservice will have its own database and will not access another microservice's database. This is fundamental when we use a modern ORM for database maintenance with migrations. Of course, the same is true for monoliths.&lt;/p&gt;

&lt;p&gt;This solution allows us to create a hybrid architecture that uses microservices without abusing them. In this way, we can reduce infrastructure and development costs while taking advantage of the key benefits of microservices.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>monoliths</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to reduce the cost of microservices architecture</title>
      <dc:creator>Luca Nicolini</dc:creator>
      <pubDate>Wed, 12 Feb 2025 11:55:47 +0000</pubDate>
      <link>https://dev.to/claranet/how-to-reduce-the-cost-of-microservices-architecture-ef4</link>
      <guid>https://dev.to/claranet/how-to-reduce-the-cost-of-microservices-architecture-ef4</guid>
      <description>&lt;p&gt;Over the past few years, more and more companies have decided to go the microservices way. Some companies are now happy with their choice, but others have unfortunately encountered various problems. In this article, we look at the cost issue of a microservices architecture and try to provide a solution.&lt;/p&gt;

&lt;p&gt;A big issue with microservices architecture is the cost of infrastructure. A microservice is a small application that runs inside a container. To create a microservices architecture, you need to manage tens or hundreds of containers. Obviously, this comes at a high cost in terms of the price of the machines running the containers, or cloud services if the containers are hosted in the cloud.&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%2Fo0wyv2o07sv03outxtu6.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%2Fo0wyv2o07sv03outxtu6.png" alt="Image description" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we're looking at AWS for cloud computing of our microservices. We need to know that in AWS we have two different ways of running containers, we can use EC2 machines or we can use Fargate.&lt;/p&gt;

&lt;p&gt;With EC2, we have to pay a fixed price to AWS to run containers. A microservices architecture can consist of hundreds of microservices, and the cost of that can be very expensive.&lt;/p&gt;

&lt;p&gt;With Fargate, the containers are serverless, so when we are not using them, they are off. We only pay for the containers while they are active.&lt;/p&gt;

&lt;p&gt;In general, from a cost perspective, serverless resources make sense for low usage, while always-on resources make sense for high usage.&lt;/p&gt;

&lt;p&gt;Within a microservices architecture, there are services that are called with high frequency and others that are called with low frequency, this makes you understand that some containers, unlike others, will be used very little and this represents a waste. A recent idea is to build a microservices architecture using serverless functions called Lambda, in this way microservices become a set of functions that only run when called. These functions are often called FaaS or Functions as a Service. This solution costs less than Fargate.&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%2Fwt17xfnsqpbbtk57ei2y.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%2Fwt17xfnsqpbbtk57ei2y.png" alt="Image description" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows an example of a serverless architecture implemented on AWS. This is a solution to save money by using a lambda serverless functions instead of microservices. This way we don't need containers and we write code without worrying about server. This is a modern solution that many companies are using today.&lt;/p&gt;

&lt;p&gt;The first problem is that we need to create a Lambda for each function, so for large application domain we'll find a large number of Lambda function. Managing too many Lambda function may not be easy.&lt;/p&gt;

&lt;p&gt;The second problem is in the resource consuming, for example using more Lambda on the same database the DBMS it can manage too connections. This applies to all resources used, not just the database.&lt;/p&gt;

&lt;p&gt;The third problem is the start time for the Lambda startup when it is called in the off state. In fact, if we call a Lambda function in the off state, it'll perform a startup which will slow down the first execution. The lifecycle of a Lambda will last for a few minutes, then it'll be back in off and we'll find a new start time for the next execution.&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%2Fluxosy6bzt8q3wxd9k7a.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%2Fluxosy6bzt8q3wxd9k7a.png" alt="Image description" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows an example of microservices encapsulated within  Lambda functions. It may look strange, but it is a powerful and versatile solution. So we can write microservices normally without thinking about concepts of serverless functions, we can deploy our microservices on Lambda functions, we can migrate our microservices to containers later.&lt;/p&gt;

&lt;p&gt;My advice is to start with microservices within lambda function until  they have low usage. When the microservice has high usage then we'll migrate to container, we can choose Fargate for high usage, EC2 for very high usage.&lt;/p&gt;

&lt;p&gt;Now I'll show you how to implement this thing in Node.js using Fastify with TypeScript.&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%2Fy0dfhiek55lb819rol6c.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%2Fy0dfhiek55lb819rol6c.png" alt="Image description" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's start by creating a route as Fastify plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { FastifyPluginAsync } from 'fastify'

const routes: FastifyPluginAsync = async server =&amp;gt; {
    server.get('/api/hello-world', async () =&amp;gt; {
        return {
            hello: 'world'
        }
    })
}

export default routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then we create a simple Fastify application that uses the plugin above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fastify from 'fastify'

const port = 5100
const server = fastify()

server.register(import('./routes'))

server.listen({ port }, () =&amp;gt; {
    console.log(`http://localhost:${port}/`)
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple application can be seen as a first step towards creating a microservice. In this case, we are talking about a microservice running in a container, because we are implementing a web server listening on port 5100.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import fastify from 'fastify'
import awsLambdaFastify from '@fastify/aws-lambda'

const server = fastify()

server.register(import('./routes'))

export const lambda = awsLambdaFastify(server)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've modified the code to create a Lambda function using '@fastify/aws-lambda'. This Lambda can then be deployed to AWS, for example using CloudFormation or Terraform to perform the deploy. As you can see, it's very easy going from container to Lambda and from Lambda to container.&lt;/p&gt;

&lt;p&gt;In this &lt;a href="https://github.com/claranet-it/fastify-serverless-starter-infra" rel="noopener noreferrer"&gt;repository&lt;/a&gt; we show an example of Terraform usage for Lambda deploy.&lt;/p&gt;

&lt;p&gt;For container orchestration, we can use EKS or ECS. ECS is the first choice if you're in AWS, but EKS is important if you're a Kubernetes expert and you want to keep using it.&lt;/p&gt;

&lt;p&gt;We've learned a way to write microservices, which run in a container or as lambda functions, and it's very easy to move from lambda to container or vice versa. So we've got a lot of control over the cost of our architecture, safely executed in the cloud.&lt;/p&gt;

&lt;p&gt;The world of microservices is in continuous evolution, I think that encapsulating microservices to serverless functions is a good practice for services with low frequency of using. I also believe that using Semi-Monolithic Architecture could become important, but we will talk about this in the next episodes.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>lambda</category>
      <category>aws</category>
      <category>programming</category>
    </item>
    <item>
      <title>From a Brown Field to One in Bloom: Revitalizing AngularJS with React</title>
      <dc:creator>Gianluca La Manna</dc:creator>
      <pubDate>Tue, 11 Feb 2025 16:34:49 +0000</pubDate>
      <link>https://dev.to/claranet/from-a-brown-field-to-one-in-bloom-revitalizing-angularjs-with-react-115k</link>
      <guid>https://dev.to/claranet/from-a-brown-field-to-one-in-bloom-revitalizing-angularjs-with-react-115k</guid>
      <description>&lt;p&gt;If you have worked at least once on a brownfield project, you know how difficult and frustrating it can be.&lt;/p&gt;

&lt;p&gt;You can use old approaches, but you're probably writing code without the Typescript superset. Furthermore, you are losing all the functionalities that a new framework has, which compromises the velocity and the devEx.&lt;/p&gt;

&lt;p&gt;We can write the entire solution with another framework. Probably, this won't be a good idea, basically for two reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time 🕰️&lt;/li&gt;
&lt;li&gt;Costs 💸&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The good news is that you can write the new features with the latest framework while keeping the old features. If you have good craftsmanship, you will be able to use the &lt;a href="https://martinfowler.com/bliki/StranglerFigApplication.html" rel="noopener noreferrer"&gt;strangler fig pattern&lt;/a&gt; by Martin Fowler, promoting a smooth and clean transition.&lt;/p&gt;

&lt;p&gt;From brownfield to one in bloom 🌸, but how?&lt;/p&gt;

&lt;h2&gt;
  
  
  AngularJS issues
&lt;/h2&gt;

&lt;p&gt;We take the example of AngularJS.&lt;/p&gt;

&lt;p&gt;The most significant risk of staying on AngularJS is safety, given that Google doesn't provide new security patches.&lt;/p&gt;

&lt;p&gt;Another big issue is the two-way-data-binding. Each change in UI is reflected in the model and vice versa.&lt;/p&gt;

&lt;p&gt;Each state change synchronizes more variables, and the use of a digest cycle can slow the application.&lt;/p&gt;

&lt;p&gt;The next example of how AngularJS makes you suffer is &lt;strong&gt;Dependency Injection&lt;/strong&gt; 💉. In AngularJS, dependencies are injected by the name of an argument.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="c1"&gt;// … &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;.toString()&lt;/code&gt; method is called, which extracts the argument names and then compares them with the already registered dependencies.&lt;br&gt;
So, when you minify the code, it stops working.&lt;/p&gt;

&lt;p&gt;Ultimately, we won't have TypeScript and all its advantages.&lt;/p&gt;

&lt;p&gt;Perhaps we have enough points to think about writing with a new framework:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Safety&lt;/li&gt;
&lt;li&gt;Two way data binding&lt;/li&gt;
&lt;li&gt;DI&lt;/li&gt;
&lt;li&gt;TS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let's see how to integrate React into the AngularJS application.&lt;/p&gt;
&lt;h2&gt;
  
  
  Scaffolding React
&lt;/h2&gt;

&lt;p&gt;The idea is to create a new folder in the AngularJS project's tree structure called &lt;code&gt;app-new&lt;/code&gt;. This will be the entry point of our React application. Here, we can install the latest version of React. Preferably, we will install React with the Vite plugin.&lt;/p&gt;

&lt;p&gt;Then, we will have a similar tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/
├── app
│   ├── assets
│   ├── modules
│   └── package.json
├── app-new
│   └── public
│       ├── src
│       └── package.json
├── assets
├── cypress
└── doc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we have two package.json. One for &lt;code&gt;app&lt;/code&gt; (AngularJS) and one for &lt;code&gt;app-new&lt;/code&gt; (React)&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration layer between two apps
&lt;/h2&gt;

&lt;p&gt;We will create an Angular component that we will call into the routes.js file. Then, we will define a new route for this component.&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-home&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;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;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;app-new-wrapper&amp;gt;&amp;lt;/app-new-wrapper&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;requiresAuth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we can pass any props for this component. &lt;/p&gt;

&lt;p&gt;Then, in the &lt;code&gt;index.js&lt;/code&gt; Angular file, we should define a scope variable. This variable defines a base URL that will be used from React.&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;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEW_APP_BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The controller, instead, should be something like that:&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="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&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;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$sce&lt;/span&gt;&lt;span class="p"&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;ctrl&lt;/span&gt; &lt;span class="o"&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;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$onInit&lt;/span&gt; &lt;span class="o"&gt;=&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;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NEW_APP_BASE_URL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$sce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trustAsResourceUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/app-new/`&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="nx"&gt;angular&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;libClient.common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appNewWrapper&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;bindings&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;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/modules/common/component/appNewWrapper/appNewWrapper.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$sce&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;controller&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;and the view&lt;br&gt;
&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;iframe&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"iframe1"&lt;/span&gt; &lt;span class="na"&gt;frameBorder=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;scrolling=&lt;/span&gt;&lt;span class="s"&gt;"no"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{$ctrl.url}}"&lt;/span&gt; &lt;span class="na"&gt;allow=&lt;/span&gt;&lt;span class="s"&gt;"camera; microphone; display-capture; geolocation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Here's a little summary:&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%2Fz8p98z0rrmoxl5k07vos.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%2Fz8p98z0rrmoxl5k07vos.png" alt="Diagram How it works" width="800" height="1034"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generally, the iframe is not a good idea for several reasons. The basic idea is to use it only for the transition from Angular to React, then remove it. With iframe, if you have SEO on your website, you may be penalized by Google indexing and have a ranking problem, in addition to various security issues.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, we will have 2 apps launched on different ports.&lt;/p&gt;

&lt;p&gt;To call our React components inside the iframe, let's define them in our AppRouter with the correct url that will open the iframe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AppRouter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;useRoutes&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;/&amp;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;h2&gt;
  
  
  Communication both frameworks
&lt;/h2&gt;

&lt;p&gt;All right! Now we might ask ourselves a rather spontaneous question:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How can I communicate between a part of my app in angular and one in react or navigate through pages?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The answer? 🥁... : &lt;code&gt;window.postMessage()&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;window.postMessage()&lt;/code&gt; method safely enables cross-origin communication between a page and an iframe embedded within it&lt;/p&gt;

&lt;p&gt;So, we create a function called &lt;code&gt;goTo&lt;/code&gt; to navigate across the pages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;goTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;NavigationParams&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&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;parent&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;

    &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;navigation&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we send a message from React to Angular, we use this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATE_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then in the Angular controller&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UPDATE_ID&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With this approach, we can integrate React into AngularJS and revitalize it. A good next step would be to rewrite the old AngularJS controllers into React components. This way, we have a smooth transition from AngularJS to React. In the end, we can remove our app-new-wrapper and iframe and delete the old app folder. Then, we will have the whole project in the React framework ✨&lt;/p&gt;

&lt;p&gt;See ya next time. 👋🏻&lt;/p&gt;

</description>
      <category>angular</category>
      <category>react</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
